<commit_before>$(function() {

  "use strict";

    var topoffset = 50; //variable for menu height
    var slideqty = $('#featured .item').length;
    var wheight = $(window).height(); //get the height of the window

    $('.fullheight').css('height', wheight); //set to window tallness

    //replace IMG inside carousels with a background image
    $('#featured .item img').each(function() {
      var imgSrc = $(this).attr('src');
      $(this).parent().css({'background-image': 'url('+imgSrc+')'});
      $(this).remove();
    });

    //adjust height of .fullheight elements on window resize
    $(window).resize(function() {
      wheight = $(window).height(); //get the height of the window
      $('.fullheight').css('height', wheight); //set to window tallness
    });

  //Activate Scrollspy
  $('body').scrollspy({
    target: 'header .navbar',
    offset: topoffset
  });

  // add inbody class
  var hash = $(this).find('li.active a').attr('href');
  if(hash !== '#featured') {
    $('header nav').addClass('inbody');
    $('#ui8ads-container').css('top','60px');

  } else {
    $('header nav').removeClass('inbody');
    $('#ui8ads-container').css('top','140px');
  }

  // Add an inbody class to nav when scrollspy event fires
  $('.navbar-fixed-top').on('activate.bs.scrollspy', function() {
    var hash = $(this).find('li.active a').attr('href');
    if(hash !== '#featured') {
      $('header nav').addClass('inbody');
    } else {
      $('header nav').removeClass('inbody');
    }
  });

  //Use smooth scrolling when clicking on navigation
  $('.navbar a[href*=#]:not([href=#])').click(function() {
    if (location.pathname.replace(/^\//,'') ===
      this.pathname.replace(/^\//,'') &&
      location.hostname === this.hostname) {
      var target = $(this.hash);
      target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
      if (target.length) {
        $('html,body').animate({
          scrollTop: target.offset().top-topoffset+2
        }, 500);
        return false;
      } //target.length
    } //click function
  }); //smooth scrolling

  //Automatically generate carousel indicators
  for (var i=0; i < slideqty; i++) {
    var insertText = '

';
    $('#featured ol').append(insertText);
  }

  $('.carousel').carousel({
    interval:'3000',
      pause:false
  });

// /////////////////////
var btnRadius = $('.cd-modal-bg').width()/2,
	left = $('.cd-modal-bg').offset().left + btnRadius,
	top = $('.cd-modal-bg').offset().top + btnRadius - $(window).scrollTop(),
	scale = scaleValue(top, left, btnRadius, $(window).height(), $(window).width());

function scaleValue( topValue, leftValue, radiusValue, windowW, windowH) {
	var maxDistHor = ( leftValue > windowW/2) ? leftValue : (windowW - leftValue),
		maxDistVert = ( topValue > windowH/2) ? topValue : (windowH - topValue);
	return Math.ceil(Math.sqrt( Math.pow(maxDistHor, 2) + Math.pow(maxDistVert, 2) )/radiusValue);
}

});

<commit_msg>preloader add<commit_after>/* -----------------------------
Pre Loader
----------------------------- */
$(window).load(function() {
	'use strict';
	$('.loading-icon').delay(500).fadeOut();
	$('#preloader').delay(800).fadeOut('slow');
});

$(function() {

  "use strict";

    var topoffset = 50; //variable for menu height
    var slideqty = $('#featured .item').length;
    var wheight = $(window).height(); //get the height of the window

    $('.fullheight').css('height', wheight); //set to window tallness

    //replace IMG inside carousels with a background image
    $('#featured .item img').each(function() {
      var imgSrc = $(this).attr('src');
      $(this).parent().css({'background-image': 'url('+imgSrc+')'});
      $(this).remove();
    });

    //adjust height of .fullheight elements on window resize
    $(window).resize(function() {
      wheight = $(window).height(); //get the height of the window
      $('.fullheight').css('height', wheight); //set to window tallness
    });

  //Activate Scrollspy
  $('body').scrollspy({
    target: 'header .navbar',
    offset: topoffset
  });

  // add inbody class
  var hash = $(this).find('li.active a').attr('href');
  if(hash !== '#featured') {
    $('header nav').addClass('inbody');
    $('#ui8ads-container').css('top','60px');

  } else {
    $('header nav').removeClass('inbody');
    $('#ui8ads-container').css('top','140px');
  }

  // Add an inbody class to nav when scrollspy event fires
  $('.navbar-fixed-top').on('activate.bs.scrollspy', function() {
    var hash = $(this).find('li.active a').attr('href');
    if(hash !== '#featured') {
      $('header nav').addClass('inbody');
    } else {
      $('header nav').removeClass('inbody');
    }
  });

  //Use smooth scrolling when clicking on navigation
  $('.navbar a[href*=#]:not([href=#])').click(function() {
    if (location.pathname.replace(/^\//,'') ===
      this.pathname.replace(/^\//,'') &&
      location.hostname === this.hostname) {
      var target = $(this.hash);
      target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
      if (target.length) {
        $('html,body').animate({
          scrollTop: target.offset().top-topoffset+2
        }, 500);
        return false;
      } //target.length
    } //click function
  }); //smooth scrolling

  //Automatically generate carousel indicators
  for (var i=0; i < slideqty; i++) {
    var insertText = '

';
    $('#featured ol').append(insertText);
  }

  $('.carousel').carousel({
    interval:'3000',
      pause:false
  });

// /////////////////////
var btnRadius = $('.cd-modal-bg').width()/2,
	left = $('.cd-modal-bg').offset().left + btnRadius,
	top = $('.cd-modal-bg').offset().top + btnRadius - $(window).scrollTop(),
	scale = scaleValue(top, left, btnRadius, $(window).height(), $(window).width());

function scaleValue( topValue, leftValue, radiusValue, windowW, windowH) {
	var maxDistHor = ( leftValue > windowW/2) ? leftValue : (windowW - leftValue),
		maxDistVert = ( topValue > windowH/2) ? topValue : (windowH - topValue);
	return Math.ceil(Math.sqrt( Math.pow(maxDistHor, 2) + Math.pow(maxDistVert, 2) )/radiusValue);
}

});

<|endoftext|>


<commit_before>/*!
 * jquery.fancytree.edit.js
 *
 * Make node titles editable.
 * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/)
 *
 * Copyright (c) 2014, Martin Wendt (http://wwWendt.de)
 *
 * Released under the MIT license
 * https://github.com/mar10/fancytree/wiki/LicenseInfo
 *
 * @version DEVELOPMENT
 * @date DEVELOPMENT
 */
/**
 * @module fancytree/edit
 */

;(function($, window, document, undefined) {

"use strict";

/*******************************************************************************
 * Private functions and variables
 */

var isMac = /Mac/.test(navigator.platform)
	// modifiers = {shift: "shiftKey", ctrl: "ctrlKey", alt: "altKey", meta: "metaKey"},
	// specialKeys = {
	// 	8: "backspace", 9: "tab", 10: "return", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
	// 	20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
	// 	37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del",
	// 	96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
	// 	104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
	// 	112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
	// 	120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 186: ";", 191: "/",
	// 	220: "\\", 222: "'", 224: "meta"
	// },
	// shiftNums = {
	// 	"`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
	// 	"8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<",
	// 	".": ">",  "/": "?",  "\\": "|"
	// }
	;

// $.ui.fancytree.isKeydownEvent = function(e, code){
// 	var i, part, partmap, partlist = code.split("+"), len = parts.length;
// 	var c = String.fromCharCode(e.which).toLowerCase();
// 	for( i = 0; i < len; i++ ) {
// 	}
// 	alert (parts.unshift());
// 	alert (parts.unshift());
// 	alert (parts.unshift());
// };

/**
 * Start inline editing of current node title.
 *
 * @alias FancytreeNode#editStart
 * @requires Fancytree
 */
$.ui.fancytree._FancytreeNodeClass.prototype.editStart = function(){
	var $input,
		node = this,
		tree = this.tree,
		local = tree.ext.edit,
		prevTitle = node.title,
		instOpts = tree.options.edit,
		$title = $(".fancytree-title", node.span),
		eventData = {node: node, tree: tree, options: tree.options};

	if( instOpts.beforeEdit.call(node, {type: "beforeEdit"}, eventData) === false){
		return false;
	}
	node.debug("editStart");
	// Disable standard Fancytree mouse- and key handling
	tree.widget._unbind();
	// #116: ext-dnd prevents the blur event, so we have to catch outer clicks
	$(document).on("mousedown.fancytree-edit", function(event){
		if( ! $(event.target).hasClass("fancytree-edit-input") ){
			node.editEnd(true, event);
		}
	});

	// Replace node with <input>
	$input = $("<input />", {
		"class": "fancytree-edit-input",
		value: prevTitle
	});
	if ( instOpts.adjustWidthOfs != null ) {
		$input.width($title.width() + instOpts.adjustWidthOfs);
	}
	if ( instOpts.inputCss != null ) {
		$input.css(instOpts.inputCss);
	}
	eventData.input = $input;

	$title.html($input);

	$.ui.fancytree.assert(!local.currentNode, "recursive edit");
	local.currentNode = this;
	// Focus <input> and bind keyboard handler
	$input
		.focus()
		.change(function(event){
			$input.addClass("fancytree-edit-dirty");
		}).keydown(function(event){
			switch( event.which ) {
			case $.ui.keyCode.ESCAPE:
				node.editEnd(false, event);
				break;
			case $.ui.keyCode.ENTER:
				node.editEnd(true, event);
				return false; // so we don't start editmode on Mac
			}
		}).blur(function(event){
			return node.editEnd(true, event);
		});

	instOpts.edit.call(node, {type: "edit"}, eventData);
};

/**
 * Stop inline editing.
 * @param {Boolean} [applyChanges=false]
 * @alias FancytreeNode#editEnd
 * @requires jquery.fancytree.edit.js
 */
$.ui.fancytree._FancytreeNodeClass.prototype.editEnd = function(applyChanges, _event){
	var node = this,
		tree = this.tree,
		local = tree.ext.edit,
		instOpts = tree.options.edit,
		$title = $(".fancytree-title", node.span),
		$input = $title.find("input.fancytree-edit-input"),
		newVal = $input.val(),
		dirty = $input.hasClass("fancytree-edit-dirty"),
		doSave = (applyChanges || (dirty && applyChanges !== false)) && (newVal !== node.title),
		eventData = {
			node: node, tree: tree, options: tree.options, originalEvent: _event,
			dirty: dirty,
			save: doSave,
			input: $input,
			value: newVal
			};

	if( instOpts.beforeClose.call(node, {type: "beforeClose"}, eventData) === false){
		return false;
	}
	if( doSave && instOpts.save.call(node, {type: "save"}, eventData) === false){
		return false;
	}
	$input
		.removeClass("fancytree-edit-dirty")
		.unbind();
	// Unbind outer-click handler
	$(document).off(".fancytree-edit");

	if( doSave ) {
		node.setTitle( newVal );
	}else{
		node.renderTitle();
	}
	// Re-enable mouse and keyboard handling
	tree.widget._bind();
	local.currentNode = null;
	node.setFocus();
	// Set keyboard focus, even if setFocus() claims 'nothing to do'
	$(tree.$container).focus();
	eventData.input = null;
	instOpts.close.call(node, {type: "close"}, eventData);
	return true;
};

$.ui.fancytree._FancytreeNodeClass.prototype.startEdit = function(){
	this.warn("FancytreeNode.startEdit() is deprecated. Use .editStart() instead.");
	return this.editStart.apply(this, arguments);
};

$.ui.fancytree._FancytreeNodeClass.prototype.endEdit = function(){
	this.warn("FancytreeNode.endEdit() is deprecated. Use .editEnd() instead.");
	return this.editEnd.apply(this, arguments);
};

///**
// * Create a new child or sibling node.
// *
// * @param {String} [mode] 'before', 'after', or 'child'
// * @lends FancytreeNode.prototype
// * @requires jquery.fancytree.edit.js
// */
//$.ui.fancytree._FancytreeNodeClass.prototype.editCreateNode = function(mode){
//	var newNode,
//		node = this,
//		tree = this.tree,
//		local = tree.ext.edit,
//		instOpts = tree.options.edit,
//		$title = $(".fancytree-title", node.span),
//		$input = $title.find("input.fancytree-edit-input"),
//		newVal = $input.val(),
//		dirty = $input.hasClass("fancytree-edit-dirty"),
//		doSave = (applyChanges || (dirty && applyChanges !== false)) && (newVal !== node.title),
//		eventData = {
//			node: node, tree: tree, options: tree.options, originalEvent: _event,
//			dirty: dirty,
//			save: doSave,
//			input: $input,
//			value: newVal
//			};
//
//	node.debug("editCreate");
//
//	if( instOpts.beforeEdit.call(node, {type: "beforeCreateNode"}, eventData) === false){
//		return false;
//	}
//	newNode = this.addNode({title: "Neuer Knoten"}, mode);
//
//	newNode.editStart();
//};

/**
 * Check if any node in this tree  in edit mode.
 *
 * @returns {FancytreeNode | null}
 * @lends Fancytree.prototype
 * @requires jquery.fancytree.edit.js
 */
$.ui.fancytree._FancytreeClass.prototype.isEditing = function(){
	return this.ext.edit.currentNode;
};

/**
 * Check if this node is in edit mode.
 * @returns {Boolean} true if node is currently beeing edited
 * @lends FancytreeNode.prototype
 * @requires jquery.fancytree.edit.js
 */
$.ui.fancytree._FancytreeNodeClass.prototype.isEditing = function(){
	return this.tree.ext.edit.currentNode === this;
};

/*******************************************************************************
 * Extension code
 */
$.ui.fancytree.registerExtension({
	name: "edit",
	version: "0.1.0",
	// Default options for this extension.
	options: {
		adjustWidthOfs: 4,   // null: don't adjust input size to content
		inputCss: {minWidth: "3em"},
		triggerCancel: ["esc", "tab", "click"],
		// triggerStart: ["f2", "dblclick", "shift+click", "mac+enter"],
		triggerStart: ["f2", "shift+click", "mac+enter"],
		beforeClose: $.noop, // Return false to prevent cancel/save (data.input is available)
		beforeEdit: $.noop,  // Return false to prevent edit mode
		close: $.noop,       // Editor was removed
		edit: $.noop,        // Editor was opened (available as data.input)
//		keypress: $.noop,    // Not yet implemented
		save: $.noop         // Save data.input.val() or return false to keep editor open
	},
	// Local attributes
	currentNode: null,

	// Override virtual methods for this extension.
	// `this`       : the Fancytree instance
	// `this._local`: the namespace that contains extension attributes and private methods (same as this.ext.EXTNAME)
	// `this._super`: the virtual function that was overridden (member of previous extension or Fancytree)
	treeInit: function(ctx){
		this._super(ctx);
		this.$container.addClass("fancytree-ext-edit");
	},
	nodeClick: function(ctx) {
		if( $.inArray("shift+click", ctx.options.edit.triggerStart) >= 0 ){
			if( ctx.originalEvent.shiftKey ){
				ctx.node.editStart();
				return false;
			}
		}
		this._super(ctx);
	},
	nodeDblclick: function(ctx) {
		if( $.inArray("dblclick", ctx.options.edit.triggerStart) >= 0 ){
			ctx.node.editStart();
		}
		return false;
	},
	nodeKeydown: function(ctx) {
		switch( ctx.originalEvent.which ) {
		case 113: // [F2]
			if( $.inArray("f2", ctx.options.edit.triggerStart) >= 0 ){
				ctx.node.editStart();
				return false;
			}
			break;
		case $.ui.keyCode.ENTER:
			if( $.inArray("mac+enter", ctx.options.edit.triggerStart) >= 0 && isMac ){
				ctx.node.editStart();
				return false;
			}
			break;
		}
		return this._super(ctx);
	}
});
}(jQuery, window, document));
<commit_msg>Fix handling of double click in edit extension I like to keep double click for expanding/collapsing nodes.<commit_after>/*!
 * jquery.fancytree.edit.js
 *
 * Make node titles editable.
 * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/)
 *
 * Copyright (c) 2014, Martin Wendt (http://wwWendt.de)
 *
 * Released under the MIT license
 * https://github.com/mar10/fancytree/wiki/LicenseInfo
 *
 * @version DEVELOPMENT
 * @date DEVELOPMENT
 */
/**
 * @module fancytree/edit
 */

;(function($, window, document, undefined) {

"use strict";

/*******************************************************************************
 * Private functions and variables
 */

var isMac = /Mac/.test(navigator.platform)
	// modifiers = {shift: "shiftKey", ctrl: "ctrlKey", alt: "altKey", meta: "metaKey"},
	// specialKeys = {
	// 	8: "backspace", 9: "tab", 10: "return", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
	// 	20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
	// 	37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del",
	// 	96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
	// 	104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
	// 	112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
	// 	120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 186: ";", 191: "/",
	// 	220: "\\", 222: "'", 224: "meta"
	// },
	// shiftNums = {
	// 	"`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
	// 	"8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<",
	// 	".": ">",  "/": "?",  "\\": "|"
	// }
	;

// $.ui.fancytree.isKeydownEvent = function(e, code){
// 	var i, part, partmap, partlist = code.split("+"), len = parts.length;
// 	var c = String.fromCharCode(e.which).toLowerCase();
// 	for( i = 0; i < len; i++ ) {
// 	}
// 	alert (parts.unshift());
// 	alert (parts.unshift());
// 	alert (parts.unshift());
// };

/**
 * Start inline editing of current node title.
 *
 * @alias FancytreeNode#editStart
 * @requires Fancytree
 */
$.ui.fancytree._FancytreeNodeClass.prototype.editStart = function(){
	var $input,
		node = this,
		tree = this.tree,
		local = tree.ext.edit,
		prevTitle = node.title,
		instOpts = tree.options.edit,
		$title = $(".fancytree-title", node.span),
		eventData = {node: node, tree: tree, options: tree.options};

	if( instOpts.beforeEdit.call(node, {type: "beforeEdit"}, eventData) === false){
		return false;
	}
	node.debug("editStart");
	// Disable standard Fancytree mouse- and key handling
	tree.widget._unbind();
	// #116: ext-dnd prevents the blur event, so we have to catch outer clicks
	$(document).on("mousedown.fancytree-edit", function(event){
		if( ! $(event.target).hasClass("fancytree-edit-input") ){
			node.editEnd(true, event);
		}
	});

	// Replace node with <input>
	$input = $("<input />", {
		"class": "fancytree-edit-input",
		value: prevTitle
	});
	if ( instOpts.adjustWidthOfs != null ) {
		$input.width($title.width() + instOpts.adjustWidthOfs);
	}
	if ( instOpts.inputCss != null ) {
		$input.css(instOpts.inputCss);
	}
	eventData.input = $input;

	$title.html($input);

	$.ui.fancytree.assert(!local.currentNode, "recursive edit");
	local.currentNode = this;
	// Focus <input> and bind keyboard handler
	$input
		.focus()
		.change(function(event){
			$input.addClass("fancytree-edit-dirty");
		}).keydown(function(event){
			switch( event.which ) {
			case $.ui.keyCode.ESCAPE:
				node.editEnd(false, event);
				break;
			case $.ui.keyCode.ENTER:
				node.editEnd(true, event);
				return false; // so we don't start editmode on Mac
			}
		}).blur(function(event){
			return node.editEnd(true, event);
		});

	instOpts.edit.call(node, {type: "edit"}, eventData);
};

/**
 * Stop inline editing.
 * @param {Boolean} [applyChanges=false]
 * @alias FancytreeNode#editEnd
 * @requires jquery.fancytree.edit.js
 */
$.ui.fancytree._FancytreeNodeClass.prototype.editEnd = function(applyChanges, _event){
	var node = this,
		tree = this.tree,
		local = tree.ext.edit,
		instOpts = tree.options.edit,
		$title = $(".fancytree-title", node.span),
		$input = $title.find("input.fancytree-edit-input"),
		newVal = $input.val(),
		dirty = $input.hasClass("fancytree-edit-dirty"),
		doSave = (applyChanges || (dirty && applyChanges !== false)) && (newVal !== node.title),
		eventData = {
			node: node, tree: tree, options: tree.options, originalEvent: _event,
			dirty: dirty,
			save: doSave,
			input: $input,
			value: newVal
			};

	if( instOpts.beforeClose.call(node, {type: "beforeClose"}, eventData) === false){
		return false;
	}
	if( doSave && instOpts.save.call(node, {type: "save"}, eventData) === false){
		return false;
	}
	$input
		.removeClass("fancytree-edit-dirty")
		.unbind();
	// Unbind outer-click handler
	$(document).off(".fancytree-edit");

	if( doSave ) {
		node.setTitle( newVal );
	}else{
		node.renderTitle();
	}
	// Re-enable mouse and keyboard handling
	tree.widget._bind();
	local.currentNode = null;
	node.setFocus();
	// Set keyboard focus, even if setFocus() claims 'nothing to do'
	$(tree.$container).focus();
	eventData.input = null;
	instOpts.close.call(node, {type: "close"}, eventData);
	return true;
};

$.ui.fancytree._FancytreeNodeClass.prototype.startEdit = function(){
	this.warn("FancytreeNode.startEdit() is deprecated. Use .editStart() instead.");
	return this.editStart.apply(this, arguments);
};

$.ui.fancytree._FancytreeNodeClass.prototype.endEdit = function(){
	this.warn("FancytreeNode.endEdit() is deprecated. Use .editEnd() instead.");
	return this.editEnd.apply(this, arguments);
};

///**
// * Create a new child or sibling node.
// *
// * @param {String} [mode] 'before', 'after', or 'child'
// * @lends FancytreeNode.prototype
// * @requires jquery.fancytree.edit.js
// */
//$.ui.fancytree._FancytreeNodeClass.prototype.editCreateNode = function(mode){
//	var newNode,
//		node = this,
//		tree = this.tree,
//		local = tree.ext.edit,
//		instOpts = tree.options.edit,
//		$title = $(".fancytree-title", node.span),
//		$input = $title.find("input.fancytree-edit-input"),
//		newVal = $input.val(),
//		dirty = $input.hasClass("fancytree-edit-dirty"),
//		doSave = (applyChanges || (dirty && applyChanges !== false)) && (newVal !== node.title),
//		eventData = {
//			node: node, tree: tree, options: tree.options, originalEvent: _event,
//			dirty: dirty,
//			save: doSave,
//			input: $input,
//			value: newVal
//			};
//
//	node.debug("editCreate");
//
//	if( instOpts.beforeEdit.call(node, {type: "beforeCreateNode"}, eventData) === false){
//		return false;
//	}
//	newNode = this.addNode({title: "Neuer Knoten"}, mode);
//
//	newNode.editStart();
//};

/**
 * Check if any node in this tree  in edit mode.
 *
 * @returns {FancytreeNode | null}
 * @lends Fancytree.prototype
 * @requires jquery.fancytree.edit.js
 */
$.ui.fancytree._FancytreeClass.prototype.isEditing = function(){
	return this.ext.edit.currentNode;
};

/**
 * Check if this node is in edit mode.
 * @returns {Boolean} true if node is currently beeing edited
 * @lends FancytreeNode.prototype
 * @requires jquery.fancytree.edit.js
 */
$.ui.fancytree._FancytreeNodeClass.prototype.isEditing = function(){
	return this.tree.ext.edit.currentNode === this;
};

/*******************************************************************************
 * Extension code
 */
$.ui.fancytree.registerExtension({
	name: "edit",
	version: "0.1.0",
	// Default options for this extension.
	options: {
		adjustWidthOfs: 4,   // null: don't adjust input size to content
		inputCss: {minWidth: "3em"},
		triggerCancel: ["esc", "tab", "click"],
		// triggerStart: ["f2", "dblclick", "shift+click", "mac+enter"],
		triggerStart: ["f2", "shift+click", "mac+enter"],
		beforeClose: $.noop, // Return false to prevent cancel/save (data.input is available)
		beforeEdit: $.noop,  // Return false to prevent edit mode
		close: $.noop,       // Editor was removed
		edit: $.noop,        // Editor was opened (available as data.input)
//		keypress: $.noop,    // Not yet implemented
		save: $.noop         // Save data.input.val() or return false to keep editor open
	},
	// Local attributes
	currentNode: null,

	// Override virtual methods for this extension.
	// `this`       : the Fancytree instance
	// `this._local`: the namespace that contains extension attributes and private methods (same as this.ext.EXTNAME)
	// `this._super`: the virtual function that was overridden (member of previous extension or Fancytree)
	treeInit: function(ctx){
		this._super(ctx);
		this.$container.addClass("fancytree-ext-edit");
	},
	nodeClick: function(ctx) {
		if( $.inArray("shift+click", ctx.options.edit.triggerStart) >= 0 ){
			if( ctx.originalEvent.shiftKey ){
				ctx.node.editStart();
				return false;
			}
		}
		this._super(ctx);
	},
	nodeDblclick: function(ctx) {
		if( $.inArray("dblclick", ctx.options.edit.triggerStart) >= 0 ){
			ctx.node.editStart();
			return false;
		}
		return this._super(ctx);
	},
	nodeKeydown: function(ctx) {
		switch( ctx.originalEvent.which ) {
		case 113: // [F2]
			if( $.inArray("f2", ctx.options.edit.triggerStart) >= 0 ){
				ctx.node.editStart();
				return false;
			}
			break;
		case $.ui.keyCode.ENTER:
			if( $.inArray("mac+enter", ctx.options.edit.triggerStart) >= 0 && isMac ){
				ctx.node.editStart();
				return false;
			}
			break;
		}
		return this._super(ctx);
	}
});
}(jQuery, window, document));
<|endoftext|>


<commit_before>import dispatcher from 'js/dispatcher';
import layerFactory from 'utils/layerFactory';
import layerKeys from 'constants/LayerConstants';
// import CartoLayer from 'js/layers/CartoLayer';
import appActions from 'actions/AppActions';
import resources from 'resources';
import Point from 'esri/geometry/Point';

class MapActions {
  //- Action to notify the store the map has changed so we can rerender UI changes
  //- if necessary
  mapUpdated () { return {}; }

  infoWindowUpdated ({target}) {
    return (target && target.getSelectedFeature && target.getSelectedFeature()) || false;
  }

  changeActiveTab (tabId) {
    return {
      id: tabId
    };
  }

  setAnalysisType (evt) {
    return {
      type: evt.target.value
    };
  }

  centerAndZoomLatLng (lat, lng) {
    brApp.map.centerAndZoom(new Point(lng, lat), 9);
  }

  //- Straight through dispatches, all have the following format
  /**
  * @param {object} - data
  * @param {boolean} - data.visible
  * @return {object} - data
  */
  toggleAnalysisModal = (data) => data;
  togglePrintModal = (data) => data;
  toggleSearchModal = (data) => data;
  toggleCanopyModal = (data) => data;
  toggleLayerModal = (data) => data;
  toggleSubscriptionsModal = (data) => data;
  toggleSubscribeModal = (data) => data;
  toggleConfirmModal = (data) => data;
  toggleTOCVisible = (data) => data;
  showLayerInfo = (layer) => layer;
  updateTimeExtent = (timeExtent) => timeExtent;
  toggleLegendVisible = () => { return {}; };
  toggleMobileTimeWidgetVisible = () => { return {}; };

  toggleLogin = (data) => data;

  deleteSubscription (subscription) {
    return subscription;
  }

  setUserSubscriptions (subscriptions) {
    return subscriptions;
  }

  updateImazonAlertSettings (type, value) {
    return { type, value };
  }

  changeBasemap (basemap) {
    return basemap;
  }

  updateCanopyDensity (density) {
    return { density };
  }

  updateActiveSlopeClass (classValue) {
    return classValue;
  }

  openTOCAccordion (groupKey) {
    return groupKey;
  }

  createLayers (map, layerPanel, activeLayers, language) {
    //- Organize and order the layers before adding them to the map
    let layers = Object.keys(layerPanel).filter((groupName) => {
      //- remove basemaps and extra layers, extra layers will be added later and basemaps
      //- handled differently elsewhere
      return groupName !== layerKeys.GROUP_BASEMAP && groupName !== layerKeys.EXTRA_LAYERS;
    }).sort((a, b) => {
      //- Sort the groups based on their order property
      return layerPanel[a].order - layerPanel[b].order;
    }).reduce((list, groupName) => {
      //- Flatten them into a single list but before that,
      //- Multiple the order by 100 so I can sort them more easily below, this is because there
      //- order numbers start at 0 for each group, so group 0, layer 1 would have order of 1
      //- while group 1 layer 1 would have order of 100, and I need to integrate with webmap layers
      return list.concat(layerPanel[groupName].layers.map((layer, index) => {
        layer.order = layer.order || index + 1;

        if (layer.order < 100) {
          layer.order = ((10 - layerPanel[groupName].order) * 100) - (layer.order);
        }
        return layer;
      }));
    }, []);

    //- Add the extra layers now that all the others have been sorted
    layers = layers.concat(layerPanel.extraLayers);

    //- make sure there's only one entry for each dynamic layer
    const uniqueLayers = [];
    const existingIds = [];
    layers.forEach(layer => {
      if (existingIds.indexOf(layer.id) === -1) {
        uniqueLayers.push(layer);
        existingIds.push(layer.id);
      }
    });
    //- If we are changing webmaps, and any layer is active, we want to make sure it shows up as active in the new map
    //- Make those updates here to the config as this will trickle down
    uniqueLayers.forEach(layer => {
      layer.visible = activeLayers.indexOf(layer.id) > -1 || layer.visible;
    });
    //- remove layers from config that have no url unless they are of type graphic(which have no url)
    //- sort by order from the layer config
    //- return an arcgis layer for each config object
    const esriLayers = uniqueLayers.filter(layer => layer && (layer.url || layer.type === 'graphic')).map((layer) => {
      return layerFactory(layer, language);
    }).sort((a, b) => a.order - b.order);
    map.addLayers(esriLayers);
    // If there is an error with a particular layer, handle that here
    map.on('layers-add-result', result => {
      const addedLayers = result.layers;
      const addedLayerIds = addedLayers.map(l => l.layer.id);
      const addedLayersCopy = addedLayers.map(l => l.layer);
      // Prepare the carto layer
      var cartoLayers = addedLayers.filter(layer => layer.layer.cartoUser);
      cartoLayers.forEach((cartoLayer) => {
        cartoLayer.layer.on('onCartoLayerAdd', evt => {
          const tempResources = resources;
          tempResources.layerPanel.GROUP_CARTO.layers = evt.target.cartoLayers;
          appActions.applySettings(tempResources);
        });
      });

      // Check for Errors
      var layerErrors = addedLayers.filter(layer => layer.error);
      if (layerErrors.length > 0) { console.error(layerErrors); }
      //- Sort the layers, Webmap layers need to be ordered, unfortunately graphics/feature
      //- layers wont be sorted, they always show on top

      // create an array (addedLayersCopy) where the largest indexes are the webmap layers
      uniqueLayers.forEach(l => {
        if (addedLayerIds.indexOf(l.id) === -1) {
          addedLayersCopy.push(l);
        }
      });
      // then reorder the webmap layers so that they draw on top of every other layer
      addedLayersCopy.forEach((l, i) => {
        if (addedLayerIds.indexOf(l.id) === -1) {
          map.reorderLayer(l, i);
        }
      });

      if (map.getLayer('labels')) {
        map.reorderLayer(map.getLayer('labels'), 200);
      }
      // Appending the mask to the end of the parent div to make sure mask is always on top of all layers
      var mask = document.getElementById('esri.Map_0_MASK');
      if(mask && mask.parentNode) {
        mask.parentNode.appendChild(mask);
      }
    });
    //- Return the layers through the dispatcher so the mapstore can update visible layers
    return {
      layers,
      map
    };
  }

  toggleAnalysisTab(bool) {
    return bool;
  }

}

export default dispatcher.createActions(MapActions);
<commit_msg>fix map drawing order - lcd -> webmap -> lc<commit_after>import dispatcher from 'js/dispatcher';
import layerFactory from 'utils/layerFactory';
import layerKeys from 'constants/LayerConstants';
// import CartoLayer from 'js/layers/CartoLayer';
import appActions from 'actions/AppActions';
import resources from 'resources';
import Point from 'esri/geometry/Point';

class MapActions {
  //- Action to notify the store the map has changed so we can rerender UI changes
  //- if necessary
  mapUpdated () { return {}; }

  infoWindowUpdated ({target}) {
    return (target && target.getSelectedFeature && target.getSelectedFeature()) || false;
  }

  changeActiveTab (tabId) {
    return {
      id: tabId
    };
  }

  setAnalysisType (evt) {
    return {
      type: evt.target.value
    };
  }

  centerAndZoomLatLng (lat, lng) {
    brApp.map.centerAndZoom(new Point(lng, lat), 9);
  }

  //- Straight through dispatches, all have the following format
  /**
  * @param {object} - data
  * @param {boolean} - data.visible
  * @return {object} - data
  */
  toggleAnalysisModal = (data) => data;
  togglePrintModal = (data) => data;
  toggleSearchModal = (data) => data;
  toggleCanopyModal = (data) => data;
  toggleLayerModal = (data) => data;
  toggleSubscriptionsModal = (data) => data;
  toggleSubscribeModal = (data) => data;
  toggleConfirmModal = (data) => data;
  toggleTOCVisible = (data) => data;
  showLayerInfo = (layer) => layer;
  updateTimeExtent = (timeExtent) => timeExtent;
  toggleLegendVisible = () => { return {}; };
  toggleMobileTimeWidgetVisible = () => { return {}; };

  toggleLogin = (data) => data;

  deleteSubscription (subscription) {
    return subscription;
  }

  setUserSubscriptions (subscriptions) {
    return subscriptions;
  }

  updateImazonAlertSettings (type, value) {
    return { type, value };
  }

  changeBasemap (basemap) {
    return basemap;
  }

  updateCanopyDensity (density) {
    return { density };
  }

  updateActiveSlopeClass (classValue) {
    return classValue;
  }

  openTOCAccordion (groupKey) {
    return groupKey;
  }

  createLayers (map, layerPanel, activeLayers, language) {
    //- Organize and order the layers before adding them to the map
    let layers = Object.keys(layerPanel).filter((groupName) => {
      //- remove basemaps and extra layers, extra layers will be added later and basemaps
      //- handled differently elsewhere
      return groupName !== layerKeys.GROUP_BASEMAP && groupName !== layerKeys.EXTRA_LAYERS;
    }).sort((a, b) => {
      //- Sort the groups based on their order property
      return layerPanel[a].order - layerPanel[b].order;
    }).reduce((list, groupName) => {
      //- Flatten them into a single list but before that,
      //- Multiple the order by 100 so I can sort them more easily below, this is because there
      //- order numbers start at 0 for each group, so group 0, layer 1 would have order of 1
      //- while group 1 layer 1 would have order of 100, and I need to integrate with webmap layers
      return list.concat(layerPanel[groupName].layers.map((layer, index) => {
        layer.order = layer.order || index + 1;

        if (layer.order < 100) {
          layer.order = ((10 - layerPanel[groupName].order) * 100) - (layer.order);
        }
        return layer;
      }));
    }, []);

    //- Add the extra layers now that all the others have been sorted
    layers = layers.concat(layerPanel.extraLayers);

    //- make sure there's only one entry for each dynamic layer
    const uniqueLayers = [];
    const existingIds = [];
    layers.forEach(layer => {
      if (existingIds.indexOf(layer.id) === -1) {
        uniqueLayers.push(layer);
        existingIds.push(layer.id);
      }
    });
    //- If we are changing webmaps, and any layer is active, we want to make sure it shows up as active in the new map
    //- Make those updates here to the config as this will trickle down
    uniqueLayers.forEach(layer => {
      layer.visible = activeLayers.indexOf(layer.id) > -1 || layer.visible;
    });
    //- remove layers from config that have no url unless they are of type graphic(which have no url)
    //- sort by order from the layer config
    //- return an arcgis layer for each config object
    const esriLayers = uniqueLayers.filter(layer => layer && (layer.url || layer.type === 'graphic')).map((layer) => {
      return layerFactory(layer, language);
    }).sort((a, b) => a.order - b.order);
    map.addLayers(esriLayers);
    // If there is an error with a particular layer, handle that here
    map.on('layers-add-result', result => {
      const addedLayers = result.layers;
      const addedLayerIds = addedLayers.map(l => l.layer.id);
      const addedLayersCopy = addedLayers.map(l => l.layer);
      // Prepare the carto layer
      var cartoLayers = addedLayers.filter(layer => layer.layer.cartoUser);
      cartoLayers.forEach((cartoLayer) => {
        cartoLayer.layer.on('onCartoLayerAdd', evt => {
          const tempResources = resources;
          tempResources.layerPanel.GROUP_CARTO.layers = evt.target.cartoLayers;
          appActions.applySettings(tempResources);
        });
      });

      // Check for Errors
      var layerErrors = addedLayers.filter(layer => layer.error);
      if (layerErrors.length > 0) { console.error(layerErrors); }
      //- Sort the layers, Webmap layers need to be ordered, unfortunately graphics/feature
      //- layers wont be sorted, they always show on top

      // create an array (addedLayersCopy) where the largest indexes are the webmap layers
      uniqueLayers.reverse().forEach((l, i) => {
        map.reorderLayer(l, i);
      });

      if (map.getLayer('labels')) {
        map.reorderLayer(map.getLayer('labels'), 200);
      }
      // Appending the mask to the end of the parent div to make sure mask is always on top of all layers
      var mask = document.getElementById('esri.Map_0_MASK');
      if(mask && mask.parentNode) {
        mask.parentNode.appendChild(mask);
      }
    });
    //- Return the layers through the dispatcher so the mapstore can update visible layers
    return {
      layers,
      map
    };
  }

  toggleAnalysisTab(bool) {
    return bool;
  }

}

export default dispatcher.createActions(MapActions);
<|endoftext|>


<commit_before>import { describe, PropTypes } from 'react-desc';

import { a11yTitlePropType, getAvailableAtBadge } from '../../utils';

const PAD_SIZES = ['xsmall', 'small', 'medium', 'large'];

const ANIMATION_TYPE = PropTypes.oneOf([
  'fadeIn', 'fadeOut', 'jiggle', 'pulse',
  'slideUp', 'slideDown', 'slideLeft', 'slideRight',
  'zoomIn', 'zoomOut']);
const ANIMATION_SHAPE = PropTypes.shape({
  type: ANIMATION_TYPE,
  delay: PropTypes.number,
  duration: PropTypes.number,
  size: PropTypes.oneOf(['xsmall', 'small', 'medium', 'large', 'xlarge']),
});

export default (Box) => {
  const DocumentedBox = describe(Box)
    .availableAt(getAvailableAtBadge('Box'))
    .description(
      'A flexible box that lays out its contents along a single direction.'
    )
    .usage(
      "import { Box } from 'grommet';\n<Box />"
    );
  DocumentedBox.propTypes = {
    a11yTitle: a11yTitlePropType,
    align: PropTypes.oneOf(['start', 'center', 'end', 'baseline', 'stretch'])
      .description('How to align the contents along the cross axis.'),
    alignContent: PropTypes.oneOf([
      'start', 'center', 'end', 'between', 'around', 'stretch',
    ])
      .description(`How to align the contents when there is extra space in
        the cross axis.`)
      .defaultValue('stretch'),
    alignSelf: PropTypes.oneOf(['start', 'center', 'end', 'stretch'])
      .description(`How to align along the cross axis when contained in
        a Box or along the column axis when contained in a Grid.`),
    animation: PropTypes.oneOfType([
      ANIMATION_TYPE,
      ANIMATION_SHAPE,
      PropTypes.arrayOf(
        PropTypes.oneOfType([ANIMATION_TYPE, ANIMATION_SHAPE]),
      ),
    ])
      .description(`Animation effect(s) to use. 'duration' and 'delay' should
        be in milliseconds. 'jiggle' and 'pulse' types are intended for
        small elements, like icons.`),
    background: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.shape({
        color: PropTypes.string,
        dark: PropTypes.bool,
        image: PropTypes.string,
        position: PropTypes.string,
        opacity: PropTypes.oneOfType([
          PropTypes.oneOf(['weak', 'medium', 'strong']),
          PropTypes.bool,
        ]),
      }),
    ])
      .description(`Either a color identifier to use for the background
        color. For example: 'neutral-1'. Or, a 'url()' for an image. Dark
        is not needed if color is provided.`),
    basis: PropTypes.oneOf([
      'xsmall', 'small', 'medium', 'large', 'xlarge', 'full',
      '1/2', '1/3', '2/3', '1/4', '3/4', 'auto',
    ])
      .description('A fixed or relative size along its container\'s main axis.'),
    border: PropTypes.oneOfType([
      PropTypes.oneOf(['top', 'left', 'bottom', 'right',
        'horizontal', 'vertical', 'all']),
      PropTypes.shape({
        color: PropTypes.string,
        side: PropTypes.oneOf(['top', 'left', 'bottom', 'right',
          'horizontal', 'vertical', 'all']),
        size: PropTypes.oneOf(['small', 'medium', 'large']),
      }),
    ])
      .description('Include a border.'),
    direction: PropTypes.oneOf(['row', 'column', 'row-responsive'])
      .description('The orientation to layout the child components in.')
      .defaultValue('column'),
    elevation: PropTypes.oneOf([
      'none', 'xsmall', 'small', 'medium', 'large', 'xlarge',
    ])
      .description(`Elevated height above the underlying context, indicated
        via a drop shadow.`)
      .defaultValue('none'),
    flex: PropTypes.oneOf(['grow', 'shrink', true, false])
      .description('Whether flex-grow and/or flex-shrink is true.'),
    fill: PropTypes.oneOf(['horizontal', 'vertical', true, false])
      .description('Whether the width and/or height should fill the container.'),
    gap: PropTypes.oneOf(['xsmall', 'small', 'medium', 'large', 'xlarge'])
      .description('The amount of spacing between child elements.'),
    gridArea: PropTypes.string.description(`The name of the area to place
      this Box in inside a parent Grid.`),
    justify: PropTypes.oneOf(['start', 'center', 'between', 'end'])
      .description('How to align the contents along the main axis.'),
    justifySelf: PropTypes.oneOf(['start', 'center', 'end', 'stretch'])
      .description(
        'How to align along the row axis when contained in a Grid.'
      ),
    margin: PropTypes.oneOfType([
      PropTypes.oneOf(['none', ...PAD_SIZES]),
      PropTypes.shape({
        bottom: PropTypes.oneOf(PAD_SIZES),
        horizontal: PropTypes.oneOf(PAD_SIZES),
        left: PropTypes.oneOf(PAD_SIZES),
        right: PropTypes.oneOf(PAD_SIZES),
        top: PropTypes.oneOf(PAD_SIZES),
        vertical: PropTypes.oneOf(PAD_SIZES),
      }),
    ])
      .description(`The amount of margin around the box. An object can
        be specified to distinguish horizontal margin, vertical margin, and
        margin on a particular side of the box`),
    overflow: PropTypes.oneOf(['auto', 'hidden', 'scroll'])
      .description('box overflow.'),
    pad: PropTypes.oneOfType([
      PropTypes.oneOf(['none', ...PAD_SIZES]),
      PropTypes.shape({
        bottom: PropTypes.oneOf(PAD_SIZES),
        horizontal: PropTypes.oneOf(PAD_SIZES),
        left: PropTypes.oneOf(PAD_SIZES),
        right: PropTypes.oneOf(PAD_SIZES),
        top: PropTypes.oneOf(PAD_SIZES),
        vertical: PropTypes.oneOf(PAD_SIZES),
      }),
    ])
      .description(`The amount of padding around the box contents. An
        object can be specified to distinguish horizontal padding, vertical
        padding, and padding on a particular side of the box`),
    responsive: PropTypes.bool.description(`Whether margin, pad, and border
      sizes should be scaled for mobile environments.`)
      .defaultValue(true),
    round: PropTypes.oneOf(['xsmall', 'small', 'medium', 'large', 'full'])
      .description('How much to round the corners.'),
    tag: PropTypes.string.description('The DOM tag to use for the element.')
      .defaultValue('div'),
    wrap: PropTypes.bool.description(`Whether children can wrap if they
      can't all fit.`),
  };
  return DocumentedBox;
};
<commit_msg>Updated Box gap documentation<commit_after>import { describe, PropTypes } from 'react-desc';

import { a11yTitlePropType, getAvailableAtBadge } from '../../utils';

const PAD_SIZES = ['xsmall', 'small', 'medium', 'large'];

const ANIMATION_TYPE = PropTypes.oneOf([
  'fadeIn', 'fadeOut', 'jiggle', 'pulse',
  'slideUp', 'slideDown', 'slideLeft', 'slideRight',
  'zoomIn', 'zoomOut']);
const ANIMATION_SHAPE = PropTypes.shape({
  type: ANIMATION_TYPE,
  delay: PropTypes.number,
  duration: PropTypes.number,
  size: PropTypes.oneOf(['xsmall', 'small', 'medium', 'large', 'xlarge']),
});

export default (Box) => {
  const DocumentedBox = describe(Box)
    .availableAt(getAvailableAtBadge('Box'))
    .description(
      'A flexible box that lays out its contents along a single direction.'
    )
    .usage(
      "import { Box } from 'grommet';\n<Box />"
    );
  DocumentedBox.propTypes = {
    a11yTitle: a11yTitlePropType,
    align: PropTypes.oneOf(['start', 'center', 'end', 'baseline', 'stretch'])
      .description('How to align the contents along the cross axis.'),
    alignContent: PropTypes.oneOf([
      'start', 'center', 'end', 'between', 'around', 'stretch',
    ])
      .description(`How to align the contents when there is extra space in
        the cross axis.`)
      .defaultValue('stretch'),
    alignSelf: PropTypes.oneOf(['start', 'center', 'end', 'stretch'])
      .description(`How to align along the cross axis when contained in
        a Box or along the column axis when contained in a Grid.`),
    animation: PropTypes.oneOfType([
      ANIMATION_TYPE,
      ANIMATION_SHAPE,
      PropTypes.arrayOf(
        PropTypes.oneOfType([ANIMATION_TYPE, ANIMATION_SHAPE]),
      ),
    ])
      .description(`Animation effect(s) to use. 'duration' and 'delay' should
        be in milliseconds. 'jiggle' and 'pulse' types are intended for
        small elements, like icons.`),
    background: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.shape({
        color: PropTypes.string,
        dark: PropTypes.bool,
        image: PropTypes.string,
        position: PropTypes.string,
        opacity: PropTypes.oneOfType([
          PropTypes.oneOf(['weak', 'medium', 'strong']),
          PropTypes.bool,
        ]),
      }),
    ])
      .description(`Either a color identifier to use for the background
        color. For example: 'neutral-1'. Or, a 'url()' for an image. Dark
        is not needed if color is provided.`),
    basis: PropTypes.oneOf([
      'xsmall', 'small', 'medium', 'large', 'xlarge', 'full',
      '1/2', '1/3', '2/3', '1/4', '3/4', 'auto',
    ])
      .description('A fixed or relative size along its container\'s main axis.'),
    border: PropTypes.oneOfType([
      PropTypes.oneOf(['top', 'left', 'bottom', 'right',
        'horizontal', 'vertical', 'all']),
      PropTypes.shape({
        color: PropTypes.string,
        side: PropTypes.oneOf(['top', 'left', 'bottom', 'right',
          'horizontal', 'vertical', 'all']),
        size: PropTypes.oneOf(['small', 'medium', 'large']),
      }),
    ])
      .description('Include a border.'),
    direction: PropTypes.oneOf(['row', 'column', 'row-responsive'])
      .description('The orientation to layout the child components in.')
      .defaultValue('column'),
    elevation: PropTypes.oneOf([
      'none', 'xsmall', 'small', 'medium', 'large', 'xlarge',
    ])
      .description(`Elevated height above the underlying context, indicated
        via a drop shadow.`)
      .defaultValue('none'),
    flex: PropTypes.oneOf(['grow', 'shrink', true, false])
      .description('Whether flex-grow and/or flex-shrink is true.'),
    fill: PropTypes.oneOf(['horizontal', 'vertical', true, false])
      .description('Whether the width and/or height should fill the container.'),
    gap: PropTypes.oneOf(['xsmall', 'small', 'medium', 'large', 'xlarge'])
      .description(`The amount of spacing between child elements. This
        should not be used in conjunction with 'wrap' as the gap elements
        will not wrap gracefully.`),
    gridArea: PropTypes.string.description(`The name of the area to place
      this Box in inside a parent Grid.`),
    justify: PropTypes.oneOf(['start', 'center', 'between', 'end'])
      .description('How to align the contents along the main axis.'),
    justifySelf: PropTypes.oneOf(['start', 'center', 'end', 'stretch'])
      .description(
        'How to align along the row axis when contained in a Grid.'
      ),
    margin: PropTypes.oneOfType([
      PropTypes.oneOf(['none', ...PAD_SIZES]),
      PropTypes.shape({
        bottom: PropTypes.oneOf(PAD_SIZES),
        horizontal: PropTypes.oneOf(PAD_SIZES),
        left: PropTypes.oneOf(PAD_SIZES),
        right: PropTypes.oneOf(PAD_SIZES),
        top: PropTypes.oneOf(PAD_SIZES),
        vertical: PropTypes.oneOf(PAD_SIZES),
      }),
    ])
      .description(`The amount of margin around the box. An object can
        be specified to distinguish horizontal margin, vertical margin, and
        margin on a particular side of the box`),
    overflow: PropTypes.oneOf(['auto', 'hidden', 'scroll'])
      .description('box overflow.'),
    pad: PropTypes.oneOfType([
      PropTypes.oneOf(['none', ...PAD_SIZES]),
      PropTypes.shape({
        bottom: PropTypes.oneOf(PAD_SIZES),
        horizontal: PropTypes.oneOf(PAD_SIZES),
        left: PropTypes.oneOf(PAD_SIZES),
        right: PropTypes.oneOf(PAD_SIZES),
        top: PropTypes.oneOf(PAD_SIZES),
        vertical: PropTypes.oneOf(PAD_SIZES),
      }),
    ])
      .description(`The amount of padding around the box contents. An
        object can be specified to distinguish horizontal padding, vertical
        padding, and padding on a particular side of the box`),
    responsive: PropTypes.bool.description(`Whether margin, pad, and border
      sizes should be scaled for mobile environments.`)
      .defaultValue(true),
    round: PropTypes.oneOf(['xsmall', 'small', 'medium', 'large', 'full'])
      .description('How much to round the corners.'),
    tag: PropTypes.string.description('The DOM tag to use for the element.')
      .defaultValue('div'),
    wrap: PropTypes.bool.description(`Whether children can wrap if they
      can't all fit.`),
  };
  return DocumentedBox;
};
<|endoftext|>


<commit_before>import React from 'react';

import SchemaForm from './SchemaForm';
import SchemaFormUtil from '../utils/SchemaFormUtil';

const METHODS_TO_BIND = [
  'handleFormChange',
  'validateForm'
];

class JobForm extends SchemaForm {
  constructor() {
    super();

    METHODS_TO_BIND.forEach((method) => {
      this[method] = this[method].bind(this);
    });
  }

  componentWillMount() {
    this.multipleDefinition = this.getNewDefinition();
    // On edit hide the id field.
    if (this.props.edit) {
      this.multipleDefinition.general.definition.forEach(function (definition) {
        if (definition.name === 'id') {
          definition.formElementClass = 'hidden';
        }
      });
    }
    this.props.getTriggerSubmit(this.handleExternalSubmit);
  }

  getDataTriple() {
    let model = this.triggerTabFormSubmit();
    return {
      model: SchemaFormUtil.processFormModel(model, this.multipleDefinition)
    };
  }

  validateForm() {
    // TODO: Overwrite the default behaviour until DCOS-7669 is fixed.
    return true;
  }
}

JobForm.defaultProps = {
  className: 'multiple-form row',
  getTriggerSubmit: function () {},
  onChange: function () {},
  schema: {}
};

JobForm.propTypes = {
  className: React.PropTypes.string,
  edit: React.PropTypes.bool,
  getTriggerSubmit: React.PropTypes.func,
  onChange: React.PropTypes.func,
  schema: React.PropTypes.object
};

module.exports = JobForm;
<commit_msg>Rename edit prop and add default value<commit_after>import React from 'react';

import SchemaForm from './SchemaForm';
import SchemaFormUtil from '../utils/SchemaFormUtil';

const METHODS_TO_BIND = [
  'handleFormChange',
  'validateForm'
];

class JobForm extends SchemaForm {
  constructor() {
    super();

    METHODS_TO_BIND.forEach((method) => {
      this[method] = this[method].bind(this);
    });
  }

  componentWillMount() {
    this.multipleDefinition = this.getNewDefinition();
    // On edit hide the id field.
    if (this.props.isEdit) {
      this.multipleDefinition.general.definition.forEach(function (definition) {
        if (definition.name === 'id') {
          definition.formElementClass = 'hidden';
        }
      });
    }
    this.props.getTriggerSubmit(this.handleExternalSubmit);
  }

  getDataTriple() {
    let model = this.triggerTabFormSubmit();
    return {
      model: SchemaFormUtil.processFormModel(model, this.multipleDefinition)
    };
  }

  validateForm() {
    // TODO: Overwrite the default behaviour until DCOS-7669 is fixed.
    return true;
  }
}

JobForm.defaultProps = {
  className: 'multiple-form row',
  getTriggerSubmit: function () {},
  isEdit: false,
  onChange: function () {},
  schema: {}
};

JobForm.propTypes = {
  className: React.PropTypes.string,
  isEdit: React.PropTypes.bool,
  getTriggerSubmit: React.PropTypes.func,
  onChange: React.PropTypes.func,
  schema: React.PropTypes.object
};

module.exports = JobForm;
<|endoftext|>


<commit_before>(()=> {
    if(typeof System !== 'undefined') {
        var archix = require('./archix');
        System.config({
            transpiler: 'typescript',
        });
        System.registerDynamic('archix', [], false, function(require, exports, module) {
            module.exports = archix;
        });
        System.import('index.ts').then(() => {
            var legend = document.getElementById('legend')
            if(legend) legend.innerHTML = "";
        }, console.error.bind(console));
    }
})();<commit_msg>Decoupled legend management<commit_after>(()=> {
    if(typeof System !== 'undefined') {
        var archix = require('./archix');
        System.config({
            transpiler: 'typescript',
        });
        System.registerDynamic('archix', [], false, function(require, exports, module) {
            module.exports = archix;
        });
        System.import('index.ts').then(() => {
            var legend = document.getElementById('archix-legend')
            if(legend) legend.style.display = 'block';
        }, console.error.bind(console));
    }
})();<|endoftext|>


<commit_before>'use strict';

angular.module('copayApp.controllers').controller('amountController', function($scope, $filter, $timeout, $ionicScrollDelegate, $ionicHistory, gettextCatalog, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, txFormatService, ongoingProcess, popupService, bwcError, payproService, profileService, bitcore, amazonService, nodeWebkitService) {

  var _id;
  var unitToSatoshi;
  var satToUnit;
  var unitDecimals;
  var satToBtc;
  var SMALL_FONT_SIZE_LIMIT = 10;
  var LENGTH_EXPRESSION_LIMIT = 19;
  var isNW = platformInfo.isNW;

  var unitIndex = 0;
  var altUnitIndex = 0;
  var availableUnits = [];
  var fiatCode;

  var fixedUnit;

  $scope.amountModel = { amount: 0 };

  $scope.isChromeApp = platformInfo.isChromeApp;
  $scope.isAndroid = platformInfo.isAndroid;
  $scope.isIos = platformInfo.isIOS;

  $scope.$on('$ionicView.leave', function() {
    angular.element($window).off('keydown');
  });

  $scope.$on("$ionicView.beforeEnter", function(event, data) {

    if (data.stateParams.shapeshiftOrderId && data.stateParams.shapeshiftOrderId.length > 0) {
      $scope.minShapeshiftAmount = parseFloat(data.stateParams.minShapeshiftAmount);
      $scope.maxShapeshiftAmount = parseFloat(data.stateParams.maxShapeshiftAmount);
      $scope.shapeshiftOrderId = data.stateParams.shapeshiftOrderId;
      $scope.fromWalletId = data.stateParams.fromWalletId;
    }

    if (data.stateParams.noPrefix) {
      $scope.showWarningMessage = data.stateParams.noPrefix != 0;
    }

    var config = configService.getSync().wallet.settings;

    function setAvailableUnits() {
      var defaults = configService.getDefaults();
      var configCache = configService.getSync();
      availableUnits = [];

      var hasBCHWallets = profileService.getWallets({
        coin: 'bch'
      }).length;

      if (hasBCHWallets) {
        availableUnits.push({
          name: 'Bitcoin Cash',
          id: 'bch',
          shortName: (configCache.bitcoinCashAlias || defaults.bitcoinCashAlias).toUpperCase(),
        });
      };

      var hasBTCWallets = profileService.getWallets({
        coin: 'btc'
      }).length;

      if (hasBTCWallets) {
        availableUnits.push({
          name: 'Bitcoin',
          id: 'btc',
          shortName: (configCache.bitcoinAlias || defaults.bitcoinAlias).toUpperCase(),
        });
      }

      unitIndex = 0;

      if (data.stateParams.coin) {
        var coins = data.stateParams.coin.split(',');
        var newAvailableUnits = [];

        lodash.each(coins, function(c) {
          var coin = lodash.find(availableUnits, {
            id: c
          });
          if (!coin) {
            $log.warn('Could not find desired coin:' + data.stateParams.coin)
          } else {
            newAvailableUnits.push(coin);
          }
        });

        if (newAvailableUnits.length > 0) {
          availableUnits = newAvailableUnits;
        }
      }

      //  currency have preference
      var fiatName;
      if (data.stateParams.currency) {
        fiatCode = data.stateParams.currency;
        altUnitIndex = unitIndex
        unitIndex = availableUnits.length;
      } else {
        fiatCode = config.alternativeIsoCode || 'USD';
        fiatName = config.alternanativeName || fiatCode;
        altUnitIndex = availableUnits.length;
      }

      availableUnits.push({
        name: fiatName || fiatCode,
        // TODO
        id: fiatCode,
        shortName: fiatCode,
        isFiat: true,
      });

      if (data.stateParams.fixedUnit) {
        fixedUnit = true;
      }

      unitIndex = lodash.findIndex(availableUnits, {
        isFiat: true
      });

      altUnitIndex = 0;
    };

    // Go to...
    _id = data.stateParams.id; // Optional (BitPay Card ID or Wallet ID)
    $scope.nextStep = data.stateParams.nextStep;

    setAvailableUnits();
    updateUnitUI();

    $scope.showMenu = $ionicHistory.backView() && ($ionicHistory.backView().stateName == 'tabs.send' || $ionicHistory.backView().stateName == 'tabs.bitpayCard');
    $scope.recipientType = data.stateParams.recipientType || null;
    $scope.toAddress = data.stateParams.toAddress;
    $scope.displayAddress = data.stateParams.displayAddress;
    $scope.toName = data.stateParams.toName;
    $scope.toEmail = data.stateParams.toEmail;
    $scope.toColor = data.stateParams.toColor;

    if (!$scope.nextStep && !data.stateParams.toAddress) {
      $log.error('Bad params at amount')
      throw ('bad params');
    }

    var reNr = /^[1234567890\.]$/;
    var reOp = /^[\*\+\-\/]$/;

    if (!$scope.isAndroid && !$scope.isIos) {
      var disableKeys = angular.element($window).on('keydown', function(e) {
        if (!e.key) return;
        if (e.which === 8) { // you can add others here inside brackets.
          e.preventDefault();
          $scope.removeDigit();
        }

        if (e.key.match(reNr)) {
          $scope.pushDigit(e.key);
        } else if (e.key.match(reOp)) {
          $scope.pushOperator(e.key);
        } else if (e.keyCode === 86) {
          if (e.ctrlKey || e.metaKey) processClipboard();
        } else if (e.keyCode === 13) $scope.finish();

        $timeout(function() {
          $scope.$apply();
        });
      });
    }

    $scope.specificAmount = $scope.specificAlternativeAmount = '';
    $scope.isCordova = platformInfo.isCordova;
    unitToSatoshi = config.unitToSatoshi;
    satToUnit = 1 / unitToSatoshi;
    satToBtc = 1 / 100000000;
    unitDecimals = config.unitDecimals;

    $scope.resetAmount();

    // in SAT ALWAYS
    if ($stateParams.toAmount) {
      $scope.amountModel.amount = (($stateParams.toAmount) * satToUnit).toFixed(unitDecimals);
    }

    $scope.processAmount();

    $timeout(function() {
      $ionicScrollDelegate.resize();
    }, 10);
  });

  $scope.goBack = function() {
    if ($scope.shapeshiftOrderId) {
      $state.go('tabs.send').then(function() {
        $ionicHistory.clearHistory();
        $state.go('tabs.home').then(function() {
            $state.transitionTo('tabs.shapeshift');
        });
      });
    } else {
      $ionicHistory.goBack();
    }
  }

  function paste(value) {
    $scope.amountModel.amount = value;
    $scope.processAmount();
    $timeout(function() {
      $scope.$apply();
    });
  };

  function processClipboard() {
    if (!isNW) return;
    var value = nodeWebkitService.readFromClipboard();
    if (value && evaluate(value) > 0) paste(evaluate(value));
  };

  $scope.sendMax = function() {
    $scope.useSendMax = true;
    $scope.finish();
  };

  $scope.toggleAlternative = function() {
    if ($scope.amountModel.amount && isExpression($scope.amountModel.amount)) {
      var amount = evaluate(format($scope.amountModel.amount));
      $scope.globalResult = '= ' + processResult(amount);
    }
  };

  function updateUnitUI() {
    $scope.unit = availableUnits[unitIndex].shortName;
    $scope.alternativeUnit = availableUnits[altUnitIndex].shortName;

    $scope.processAmount();
    $log.debug('Update unit coin @amount unit:' + $scope.unit + " alternativeUnit:" + $scope.alternativeUnit);
  };

  $scope.changeUnit = function() {

    if ($scope.alternativeAmount == 0) {
      $scope.alternativeAmount = null;
    }

    if (fixedUnit) return;

    if (!(availableUnits[unitIndex].isFiat && availableUnits.length > 2 && altUnitIndex == 0)) {
      unitIndex++;
      if (unitIndex >= availableUnits.length) unitIndex = 0;
    }

    if (availableUnits[unitIndex].isFiat) {
      altUnitIndex = altUnitIndex == 0 && availableUnits.length > 2 ? 1 : 0;
    } else {
      altUnitIndex = lodash.findIndex(availableUnits, {
        isFiat: true
      });
    }

    updateUnitUI();
  };

  $scope.changeAlternativeUnit = function() {

    // Do nothing is fiat is not main unit
    if (!availableUnits[unitIndex].isFiat) return;

    var nextCoin = lodash.findIndex(availableUnits, function(x) {
      if (x.isFiat) return false;
      if (x.id == availableUnits[altUnitIndex].id) return false;
      return true;
    });

    if (nextCoin >= 0) {
      altUnitIndex = nextCoin;
      updateUnitUI();
    }
  };

  function checkFontSize() {
    if ($scope.amountModel.amount && $scope.amountModel.amount.length >= SMALL_FONT_SIZE_LIMIT) $scope.smallFont = true;
    else $scope.smallFont = false;
  };

  $scope.pushDigit = function(digit) {
    if ($scope.amountModel.amount && $scope.amountModel.amount.length >= LENGTH_EXPRESSION_LIMIT) return;
    if (!$scope.isAndroid && !$scope.isIos && $scope.amountModel.amount.indexOf('.') > -1 && digit == '.') return;
    if (availableUnits[unitIndex].isFiat && $scope.amountModel.amount.indexOf('.') > -1 && $scope.amountModel.amount[$scope.amountModel.amount.indexOf('.') + 2]) return;

    $scope.amountModel.amount = ($scope.amountModel.amount + digit).replace('..', '.');
    checkFontSize();
    $scope.processAmount();
  };

  $scope.pushOperator = function(operator) {
    if (!$scope.amountModel.amount || $scope.amountModel.amount.length == 0) return;
    $scope.amountModel.amount = _pushOperator($scope.amountModel.amount);

    function _pushOperator(val) {
      if (!isOperator(lodash.last(val))) {
        return val + operator;
      } else {
        return val.slice(0, -1) + operator;
      }
    };
  };

  function isOperator(val) {
    var regex = /[\/\-\+\x\*]/;
    return regex.test(val);
  };

  function isExpression(val) {
    var regex = /^\.?\d+(\.?\d+)?([\/\-\+\*x]\d?\.?\d+)+$/;
    return regex.test(val);
  };

  $scope.removeDigit = function() {
    $scope.amountModel.amount = ($scope.amountModel.amount).toString().slice(0, -1);
    $scope.processAmount();
    checkFontSize();
  };

  $scope.resetAmount = function() {
    $scope.amountModel.amount = $scope.alternativeAmount = $scope.globalResult = '';
    $scope.allowSend = false;
    checkFontSize();
  };

  $scope.processAmount = function() {
    var formatedValue = format($scope.amountModel.amount);
    var result = evaluate(formatedValue);
    $scope.allowSend = lodash.isNumber(result) && +result > 0
      && (!$scope.shapeshiftOrderId
          || (result >= $scope.minShapeshiftAmount && result <= $scope.maxShapeshiftAmount));

    if (lodash.isNumber(result)) {
      $scope.globalResult = isExpression($scope.amountModel.amount) ? '= ' + processResult(result) : '';

      if (availableUnits[unitIndex].isFiat) {

        var a = fromFiat(result);
        if (a) {
          $scope.alternativeAmount = txFormatService.formatAmount(a * unitToSatoshi, true);
        } else {
          if (result) {
            $scope.alternativeAmount = 'N/A';
          } else {
            $scope.alternativeAmount = null;
          }
          $scope.allowSend = false;
        }
      } else {
        $scope.alternativeAmount = $filter('formatFiatAmount')(toFiat(result));
      }
    }
  };

  function processResult(val) {
    if (availableUnits[unitIndex].isFiat) return $filter('formatFiatAmount')(val);
    else return txFormatService.formatAmount(val.toFixed(unitDecimals) * unitToSatoshi, true);
  };

  function fromFiat(val) {
    return parseFloat((rateService.fromFiat(val, fiatCode, availableUnits[altUnitIndex].id) * satToUnit).toFixed(unitDecimals));
  };

  function toFiat(val) {
    if (!rateService.getRate(fiatCode)) return;

    return parseFloat((rateService.toFiat(val * unitToSatoshi, fiatCode, availableUnits[unitIndex].id)).toFixed(2));
  };

  function evaluate(val) {
    var result;
    try {
      result = $scope.$eval(val);
    } catch (e) {
      return 0;
    }
    if (!lodash.isFinite(result)) return 0;
    return result;
  };

  function format(val) {
    if (!val) return;

    var result = val.toString();

    if (isOperator(lodash.last(val))) result = result.slice(0, -1);

    return result.replace('x', '*');
  };

  $scope.finish = function() {

    function finish() {
      var unit = availableUnits[unitIndex];
      var _amount = evaluate(format($scope.amountModel.amount));
      var coin = unit.id;
      if (unit.isFiat) {
        coin = availableUnits[altUnitIndex].id;
      }

      if ($scope.nextStep) {
        $state.transitionTo($scope.nextStep, {
          id: _id,
          amount: $scope.useSendMax ? null : _amount,
          currency: unit.id.toUpperCase(),
          coin: coin,
          useSendMax: $scope.useSendMax
        });
      } else {
        var amount = _amount;

        if (unit.isFiat) {
          amount = (fromFiat(amount) * unitToSatoshi).toFixed(0);
        } else {
          amount = (amount * unitToSatoshi).toFixed(0);
        }

        var confirmData = {
          recipientType: $scope.recipientType,
          toAmount: amount,
          toAddress: $scope.toAddress,
          displayAddress: $scope.displayAddress || $scope.toAddress,
          toName: $scope.toName,
          toEmail: $scope.toEmail,
          toColor: $scope.toColor,
          coin: coin,
          useSendMax: $scope.useSendMax,
        };

        if ($scope.shapeshiftOrderId) {
          var shapeshiftOrderUrl = 'https://www.shapeshift.io/#/status/';
          shapeshiftOrderUrl += $scope.shapeshiftOrderId;
          confirmData.description = shapeshiftOrderUrl;
          confirmData.fromWalletId = $scope.fromWalletId;

          if (confirmData.useSendMax) {
            var wallet = lodash.find(profileService.getWallets({ coin: coin }),
              function(w) {
                return w.id == $scope.fromWalletId;
              });

            var balance = parseFloat(wallet.cachedBalance.substring(0, wallet.cachedBalance.length-4));
            if (balance < $scope.minShapeshiftAmount * 1.04) {
              confirmData.useSendMax = false;
              confirmData.toAmount = $scope.minShapeshiftAmount * unitToSatoshi;
            } else if (balance > $scope.maxShapeshiftAmount) {
              confirmData.useSendMax = false;
              confirmData.toAmount = $scope.maxShapeshiftAmount * unitToSatoshi * 0.99;
            }
          }
        }

        $state.transitionTo('tabs.send.confirm', confirmData);
      }
      $scope.useSendMax = null;
    }

    if ($scope.showWarningMessage) {
      var message = 'Are you sure you want to send ' + $scope.unit.toUpperCase()  + '?';
      popupService.showConfirm(message, null, 'Yes', 'No', function(res) {
        if (!res) return;
        finish();
      });
    } else {
      finish();
    }

  };
});
<commit_msg>fixed warning message but where it displayed fiat instead of bch or btc<commit_after>'use strict';

angular.module('copayApp.controllers').controller('amountController', function($scope, $filter, $timeout, $ionicScrollDelegate, $ionicHistory, gettextCatalog, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, txFormatService, ongoingProcess, popupService, bwcError, payproService, profileService, bitcore, amazonService, nodeWebkitService) {

  var _id;
  var unitToSatoshi;
  var satToUnit;
  var unitDecimals;
  var satToBtc;
  var SMALL_FONT_SIZE_LIMIT = 10;
  var LENGTH_EXPRESSION_LIMIT = 19;
  var isNW = platformInfo.isNW;

  var unitIndex = 0;
  var altUnitIndex = 0;
  var availableUnits = [];
  var fiatCode;

  var fixedUnit;

  $scope.amountModel = { amount: 0 };

  $scope.isChromeApp = platformInfo.isChromeApp;
  $scope.isAndroid = platformInfo.isAndroid;
  $scope.isIos = platformInfo.isIOS;

  $scope.$on('$ionicView.leave', function() {
    angular.element($window).off('keydown');
  });

  $scope.$on("$ionicView.beforeEnter", function(event, data) {

    if (data.stateParams.shapeshiftOrderId && data.stateParams.shapeshiftOrderId.length > 0) {
      $scope.minShapeshiftAmount = parseFloat(data.stateParams.minShapeshiftAmount);
      $scope.maxShapeshiftAmount = parseFloat(data.stateParams.maxShapeshiftAmount);
      $scope.shapeshiftOrderId = data.stateParams.shapeshiftOrderId;
      $scope.fromWalletId = data.stateParams.fromWalletId;
    }

    if (data.stateParams.noPrefix) {
      $scope.showWarningMessage = data.stateParams.noPrefix != 0;
    }

    var config = configService.getSync().wallet.settings;

    function setAvailableUnits() {
      var defaults = configService.getDefaults();
      var configCache = configService.getSync();
      availableUnits = [];

      var hasBCHWallets = profileService.getWallets({
        coin: 'bch'
      }).length;

      if (hasBCHWallets) {
        availableUnits.push({
          name: 'Bitcoin Cash',
          id: 'bch',
          shortName: (configCache.bitcoinCashAlias || defaults.bitcoinCashAlias).toUpperCase(),
        });
      };

      var hasBTCWallets = profileService.getWallets({
        coin: 'btc'
      }).length;

      if (hasBTCWallets) {
        availableUnits.push({
          name: 'Bitcoin',
          id: 'btc',
          shortName: (configCache.bitcoinAlias || defaults.bitcoinAlias).toUpperCase(),
        });
      }

      unitIndex = 0;

      if (data.stateParams.coin) {
        var coins = data.stateParams.coin.split(',');
        var newAvailableUnits = [];

        lodash.each(coins, function(c) {
          var coin = lodash.find(availableUnits, {
            id: c
          });
          if (!coin) {
            $log.warn('Could not find desired coin:' + data.stateParams.coin)
          } else {
            newAvailableUnits.push(coin);
          }
        });

        if (newAvailableUnits.length > 0) {
          availableUnits = newAvailableUnits;
        }
      }

      //  currency have preference
      var fiatName;
      if (data.stateParams.currency) {
        fiatCode = data.stateParams.currency;
        altUnitIndex = unitIndex
        unitIndex = availableUnits.length;
      } else {
        fiatCode = config.alternativeIsoCode || 'USD';
        fiatName = config.alternanativeName || fiatCode;
        altUnitIndex = availableUnits.length;
      }

      availableUnits.push({
        name: fiatName || fiatCode,
        // TODO
        id: fiatCode,
        shortName: fiatCode,
        isFiat: true,
      });

      if (data.stateParams.fixedUnit) {
        fixedUnit = true;
      }

      unitIndex = lodash.findIndex(availableUnits, {
        isFiat: true
      });

      altUnitIndex = 0;
    };

    // Go to...
    _id = data.stateParams.id; // Optional (BitPay Card ID or Wallet ID)
    $scope.nextStep = data.stateParams.nextStep;

    setAvailableUnits();
    updateUnitUI();

    $scope.showMenu = $ionicHistory.backView() && ($ionicHistory.backView().stateName == 'tabs.send' || $ionicHistory.backView().stateName == 'tabs.bitpayCard');
    $scope.recipientType = data.stateParams.recipientType || null;
    $scope.toAddress = data.stateParams.toAddress;
    $scope.displayAddress = data.stateParams.displayAddress;
    $scope.toName = data.stateParams.toName;
    $scope.toEmail = data.stateParams.toEmail;
    $scope.toColor = data.stateParams.toColor;

    if (!$scope.nextStep && !data.stateParams.toAddress) {
      $log.error('Bad params at amount')
      throw ('bad params');
    }

    var reNr = /^[1234567890\.]$/;
    var reOp = /^[\*\+\-\/]$/;

    if (!$scope.isAndroid && !$scope.isIos) {
      var disableKeys = angular.element($window).on('keydown', function(e) {
        if (!e.key) return;
        if (e.which === 8) { // you can add others here inside brackets.
          e.preventDefault();
          $scope.removeDigit();
        }

        if (e.key.match(reNr)) {
          $scope.pushDigit(e.key);
        } else if (e.key.match(reOp)) {
          $scope.pushOperator(e.key);
        } else if (e.keyCode === 86) {
          if (e.ctrlKey || e.metaKey) processClipboard();
        } else if (e.keyCode === 13) $scope.finish();

        $timeout(function() {
          $scope.$apply();
        });
      });
    }

    $scope.specificAmount = $scope.specificAlternativeAmount = '';
    $scope.isCordova = platformInfo.isCordova;
    unitToSatoshi = config.unitToSatoshi;
    satToUnit = 1 / unitToSatoshi;
    satToBtc = 1 / 100000000;
    unitDecimals = config.unitDecimals;

    $scope.resetAmount();

    // in SAT ALWAYS
    if ($stateParams.toAmount) {
      $scope.amountModel.amount = (($stateParams.toAmount) * satToUnit).toFixed(unitDecimals);
    }

    $scope.processAmount();

    $timeout(function() {
      $ionicScrollDelegate.resize();
    }, 10);
  });

  $scope.goBack = function() {
    if ($scope.shapeshiftOrderId) {
      $state.go('tabs.send').then(function() {
        $ionicHistory.clearHistory();
        $state.go('tabs.home').then(function() {
            $state.transitionTo('tabs.shapeshift');
        });
      });
    } else {
      $ionicHistory.goBack();
    }
  }

  function paste(value) {
    $scope.amountModel.amount = value;
    $scope.processAmount();
    $timeout(function() {
      $scope.$apply();
    });
  };

  function processClipboard() {
    if (!isNW) return;
    var value = nodeWebkitService.readFromClipboard();
    if (value && evaluate(value) > 0) paste(evaluate(value));
  };

  $scope.sendMax = function() {
    $scope.useSendMax = true;
    $scope.finish();
  };

  $scope.toggleAlternative = function() {
    if ($scope.amountModel.amount && isExpression($scope.amountModel.amount)) {
      var amount = evaluate(format($scope.amountModel.amount));
      $scope.globalResult = '= ' + processResult(amount);
    }
  };

  function updateUnitUI() {
    $scope.unit = availableUnits[unitIndex].shortName;
    $scope.alternativeUnit = availableUnits[altUnitIndex].shortName;

    $scope.processAmount();
    $log.debug('Update unit coin @amount unit:' + $scope.unit + " alternativeUnit:" + $scope.alternativeUnit);
  };

  $scope.changeUnit = function() {

    if ($scope.alternativeAmount == 0) {
      $scope.alternativeAmount = null;
    }

    if (fixedUnit) return;

    if (!(availableUnits[unitIndex].isFiat && availableUnits.length > 2 && altUnitIndex == 0)) {
      unitIndex++;
      if (unitIndex >= availableUnits.length) unitIndex = 0;
    }

    if (availableUnits[unitIndex].isFiat) {
      altUnitIndex = altUnitIndex == 0 && availableUnits.length > 2 ? 1 : 0;
    } else {
      altUnitIndex = lodash.findIndex(availableUnits, {
        isFiat: true
      });
    }

    updateUnitUI();
  };

  $scope.changeAlternativeUnit = function() {

    // Do nothing is fiat is not main unit
    if (!availableUnits[unitIndex].isFiat) return;

    var nextCoin = lodash.findIndex(availableUnits, function(x) {
      if (x.isFiat) return false;
      if (x.id == availableUnits[altUnitIndex].id) return false;
      return true;
    });

    if (nextCoin >= 0) {
      altUnitIndex = nextCoin;
      updateUnitUI();
    }
  };

  function checkFontSize() {
    if ($scope.amountModel.amount && $scope.amountModel.amount.length >= SMALL_FONT_SIZE_LIMIT) $scope.smallFont = true;
    else $scope.smallFont = false;
  };

  $scope.pushDigit = function(digit) {
    if ($scope.amountModel.amount && $scope.amountModel.amount.length >= LENGTH_EXPRESSION_LIMIT) return;
    if (!$scope.isAndroid && !$scope.isIos && $scope.amountModel.amount.indexOf('.') > -1 && digit == '.') return;
    if (availableUnits[unitIndex].isFiat && $scope.amountModel.amount.indexOf('.') > -1 && $scope.amountModel.amount[$scope.amountModel.amount.indexOf('.') + 2]) return;

    $scope.amountModel.amount = ($scope.amountModel.amount + digit).replace('..', '.');
    checkFontSize();
    $scope.processAmount();
  };

  $scope.pushOperator = function(operator) {
    if (!$scope.amountModel.amount || $scope.amountModel.amount.length == 0) return;
    $scope.amountModel.amount = _pushOperator($scope.amountModel.amount);

    function _pushOperator(val) {
      if (!isOperator(lodash.last(val))) {
        return val + operator;
      } else {
        return val.slice(0, -1) + operator;
      }
    };
  };

  function isOperator(val) {
    var regex = /[\/\-\+\x\*]/;
    return regex.test(val);
  };

  function isExpression(val) {
    var regex = /^\.?\d+(\.?\d+)?([\/\-\+\*x]\d?\.?\d+)+$/;
    return regex.test(val);
  };

  $scope.removeDigit = function() {
    $scope.amountModel.amount = ($scope.amountModel.amount).toString().slice(0, -1);
    $scope.processAmount();
    checkFontSize();
  };

  $scope.resetAmount = function() {
    $scope.amountModel.amount = $scope.alternativeAmount = $scope.globalResult = '';
    $scope.allowSend = false;
    checkFontSize();
  };

  $scope.processAmount = function() {
    var formatedValue = format($scope.amountModel.amount);
    var result = evaluate(formatedValue);
    $scope.allowSend = lodash.isNumber(result) && +result > 0
      && (!$scope.shapeshiftOrderId
          || (result >= $scope.minShapeshiftAmount && result <= $scope.maxShapeshiftAmount));

    if (lodash.isNumber(result)) {
      $scope.globalResult = isExpression($scope.amountModel.amount) ? '= ' + processResult(result) : '';

      if (availableUnits[unitIndex].isFiat) {

        var a = fromFiat(result);
        if (a) {
          $scope.alternativeAmount = txFormatService.formatAmount(a * unitToSatoshi, true);
        } else {
          if (result) {
            $scope.alternativeAmount = 'N/A';
          } else {
            $scope.alternativeAmount = null;
          }
          $scope.allowSend = false;
        }
      } else {
        $scope.alternativeAmount = $filter('formatFiatAmount')(toFiat(result));
      }
    }
  };

  function processResult(val) {
    if (availableUnits[unitIndex].isFiat) return $filter('formatFiatAmount')(val);
    else return txFormatService.formatAmount(val.toFixed(unitDecimals) * unitToSatoshi, true);
  };

  function fromFiat(val) {
    return parseFloat((rateService.fromFiat(val, fiatCode, availableUnits[altUnitIndex].id) * satToUnit).toFixed(unitDecimals));
  };

  function toFiat(val) {
    if (!rateService.getRate(fiatCode)) return;

    return parseFloat((rateService.toFiat(val * unitToSatoshi, fiatCode, availableUnits[unitIndex].id)).toFixed(2));
  };

  function evaluate(val) {
    var result;
    try {
      result = $scope.$eval(val);
    } catch (e) {
      return 0;
    }
    if (!lodash.isFinite(result)) return 0;
    return result;
  };

  function format(val) {
    if (!val) return;

    var result = val.toString();

    if (isOperator(lodash.last(val))) result = result.slice(0, -1);

    return result.replace('x', '*');
  };

  $scope.finish = function() {

    function finish() {
      var unit = availableUnits[unitIndex];
      var _amount = evaluate(format($scope.amountModel.amount));
      var coin = unit.id;
      if (unit.isFiat) {
        coin = availableUnits[altUnitIndex].id;
      }

      if ($scope.nextStep) {
        $state.transitionTo($scope.nextStep, {
          id: _id,
          amount: $scope.useSendMax ? null : _amount,
          currency: unit.id.toUpperCase(),
          coin: coin,
          useSendMax: $scope.useSendMax
        });
      } else {
        var amount = _amount;

        if (unit.isFiat) {
          amount = (fromFiat(amount) * unitToSatoshi).toFixed(0);
        } else {
          amount = (amount * unitToSatoshi).toFixed(0);
        }

        var confirmData = {
          recipientType: $scope.recipientType,
          toAmount: amount,
          toAddress: $scope.toAddress,
          displayAddress: $scope.displayAddress || $scope.toAddress,
          toName: $scope.toName,
          toEmail: $scope.toEmail,
          toColor: $scope.toColor,
          coin: coin,
          useSendMax: $scope.useSendMax,
        };

        if ($scope.shapeshiftOrderId) {
          var shapeshiftOrderUrl = 'https://www.shapeshift.io/#/status/';
          shapeshiftOrderUrl += $scope.shapeshiftOrderId;
          confirmData.description = shapeshiftOrderUrl;
          confirmData.fromWalletId = $scope.fromWalletId;

          if (confirmData.useSendMax) {
            var wallet = lodash.find(profileService.getWallets({ coin: coin }),
              function(w) {
                return w.id == $scope.fromWalletId;
              });

            var balance = parseFloat(wallet.cachedBalance.substring(0, wallet.cachedBalance.length-4));
            if (balance < $scope.minShapeshiftAmount * 1.04) {
              confirmData.useSendMax = false;
              confirmData.toAmount = $scope.minShapeshiftAmount * unitToSatoshi;
            } else if (balance > $scope.maxShapeshiftAmount) {
              confirmData.useSendMax = false;
              confirmData.toAmount = $scope.maxShapeshiftAmount * unitToSatoshi * 0.99;
            }
          }
        }

        $state.transitionTo('tabs.send.confirm', confirmData);
      }
      $scope.useSendMax = null;
    }

    if ($scope.showWarningMessage) {
      var u = $scope.unit == 'BCH' || $scope.unit == 'BTC' ? $scope.unit : $scope.alternativeUnit;
      var message = 'Are you sure you want to send ' + u.toUpperCase()  + '?';
      popupService.showConfirm(message, null, 'Yes', 'No', function(res) {
        if (!res) return;
        finish();
      });
    } else {
      finish();
    }

  };
});
<|endoftext|>


<commit_before>'use strict';

angular.module('copayApp.controllers').controller('amountController', function($scope, $filter, $timeout, $ionicScrollDelegate, $ionicHistory, gettextCatalog, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, txFormatService, ongoingProcess, popupService, bwcError, payproService, profileService, bitcore, amazonService) {
  var _cardId;
  var unitToSatoshi;
  var satToUnit;
  var unitDecimals;
  var satToBtc;
  var SMALL_FONT_SIZE_LIMIT = 10;
  var LENGTH_EXPRESSION_LIMIT = 19;
  $scope.isChromeApp = platformInfo.isChromeApp;

  $scope.$on('$ionicView.leave', function() {
    angular.element($window).off('keydown');
  });

  $scope.$on("$ionicView.beforeEnter", function(event, data) {

    // Go to...
    _cardId = data.stateParams.id; // Optional (BitPay Card ID)
    $scope.nextStep = data.stateParams.nextStep;
    $scope.currency = data.stateParams.currency;
    $scope.forceCurrency = data.stateParams.forceCurrency;

    $scope.showMenu = $ionicHistory.backView() && $ionicHistory.backView().stateName == 'tabs.send';
    $scope.recipientType = data.stateParams.recipientType || null;
    $scope.toAddress = data.stateParams.toAddress;
    $scope.toName = data.stateParams.toName;
    $scope.toEmail = data.stateParams.toEmail;
    $scope.showAlternativeAmount = !!$scope.nextStep;
    $scope.toColor = data.stateParams.toColor;
    $scope.showSendMax = false;

    $scope.customAmount = data.stateParams.customAmount;

    if (!$scope.nextStep && !data.stateParams.toAddress) {
      $log.error('Bad params at amount')
      throw ('bad params');
    }

    var reNr = /^[1234567890\.]$/;
    var reOp = /^[\*\+\-\/]$/;

    var disableKeys = angular.element($window).on('keydown', function(e) {
      if (e.which === 8) { // you can add others here inside brackets.
        e.preventDefault();
        $scope.removeDigit();
      }

      if (e.key && e.key.match(reNr))
        $scope.pushDigit(e.key);

      else if (e.key && e.key.match(reOp))
        $scope.pushOperator(e.key);

      else if (e.key && e.key == 'Enter')
        $scope.finish();

      $timeout(function() {
        $scope.$apply();
      });
    });

    var config = configService.getSync().wallet.settings;
    $scope.unitName = config.unitName;
    if (data.stateParams.currency) {
      $scope.alternativeIsoCode = data.stateParams.currency;
    }
    $scope.specificAmount = $scope.specificAlternativeAmount = '';
    $scope.isCordova = platformInfo.isCordova;
    unitToSatoshi = config.unitToSatoshi;
    satToUnit = 1 / unitToSatoshi;
    satToBtc = 1 / 100000000;
    unitDecimals = config.unitDecimals;

    $scope.resetAmount();

    // in SAT ALWAYS
    if ($stateParams.toAmount) {
      $scope.amount = (($stateParams.toAmount) * satToUnit).toFixed(unitDecimals);
    }

    processAmount($scope.amount);

    $timeout(function() {
      $ionicScrollDelegate.resize();
    }, 10);
  });

  $scope.showSendMaxMenu = function() {
    $scope.showSendMax = true;
  };

  $scope.sendMax = function() {
    $scope.showSendMax = false;
    $state.transitionTo('tabs.send.confirm', {
      recipientType: $scope.recipientType,
      toAmount: null,
      toAddress: $scope.toAddress,
      toName: $scope.toName,
      toEmail: $scope.toEmail,
      toColor: $scope.toColor,
      useSendMax: true,
    });
  };

  $scope.toggleAlternative = function() {
    if ($scope.forceCurrency) return;
    $scope.showAlternativeAmount = !$scope.showAlternativeAmount;

    if ($scope.amount && isExpression($scope.amount)) {
      var amount = evaluate(format($scope.amount));
      $scope.globalResult = '= ' + processResult(amount);
    }
  };

  function checkFontSize() {
    if ($scope.amount && $scope.amount.length >= SMALL_FONT_SIZE_LIMIT) $scope.smallFont = true;
    else $scope.smallFont = false;
  };

  $scope.pushDigit = function(digit) {
    if ($scope.amount && $scope.amount.length >= LENGTH_EXPRESSION_LIMIT) return;
    if ($scope.amount.indexOf('.') > -1 && digit == '.') return;
    if ($scope.showAlternativeAmount && $scope.amount.indexOf('.') > -1 && $scope.amount[$scope.amount.indexOf('.') + 2]) return;

    $scope.amount = ($scope.amount + digit).replace('..', '.');
    checkFontSize();
    processAmount($scope.amount);
  };

  $scope.pushOperator = function(operator) {
    if (!$scope.amount || $scope.amount.length == 0) return;
    $scope.amount = _pushOperator($scope.amount);

    function _pushOperator(val) {
      if (!isOperator(lodash.last(val))) {
        return val + operator;
      } else {
        return val.slice(0, -1) + operator;
      }
    };
  };

  function isOperator(val) {
    var regex = /[\/\-\+\x\*]/;
    return regex.test(val);
  };

  function isExpression(val) {
    var regex = /^\.?\d+(\.?\d+)?([\/\-\+\*x]\d?\.?\d+)+$/;
    return regex.test(val);
  };

  $scope.removeDigit = function() {
    $scope.amount = $scope.amount.slice(0, -1);
    processAmount($scope.amount);
    checkFontSize();
  };

  $scope.resetAmount = function() {
    $scope.amount = $scope.alternativeResult = $scope.amountResult = $scope.globalResult = '';
    $scope.allowSend = false;
    checkFontSize();
  };

  function processAmount(val) {
    if (!val) {
      $scope.resetAmount();
      return;
    }

    var formatedValue = format(val);
    var result = evaluate(formatedValue);
    $scope.allowSend = lodash.isNumber(result) && +result > 0;
    if (lodash.isNumber(result)) {
      $scope.globalResult = isExpression(val) ? '= ' + processResult(result) : '';
      $scope.amountResult = $filter('formatFiatAmount')(toFiat(result));
      $scope.alternativeResult = txFormatService.formatAmount(fromFiat(result) * unitToSatoshi, true);
    }
  };

  function processResult(val) {
    if ($scope.showAlternativeAmount)
      return $filter('formatFiatAmount')(val);
    else
      return txFormatService.formatAmount(val.toFixed(unitDecimals) * unitToSatoshi, true);
  };

  function fromFiat(val) {
    return parseFloat((rateService.fromFiat(val, $scope.alternativeIsoCode) * satToUnit).toFixed(unitDecimals));
  };

  function toFiat(val) {
    return parseFloat((rateService.toFiat(val * unitToSatoshi, $scope.alternativeIsoCode)).toFixed(2));
  };

  function evaluate(val) {
    var result;
    try {
      result = $scope.$eval(val);
    } catch (e) {
      return 0;
    }
    if (!lodash.isFinite(result)) return 0;
    return result;
  };

  function format(val) {
    var result = val.toString();

    if (isOperator(lodash.last(val)))
      result = result.slice(0, -1);

    return result.replace('x', '*');
  };

  $scope.finish = function() {
    var _amount = evaluate(format($scope.amount));

    if ($scope.nextStep) {
      $state.transitionTo($scope.nextStep, {
        id: _cardId,
        amount: _amount,
        currency: $scope.showAlternativeAmount ? $scope.alternativeIsoCode : ''
      });
    } else {
      var amount = $scope.showAlternativeAmount ? fromFiat(_amount) : _amount;
      if ($scope.customAmount) {
        $state.transitionTo('tabs.receive.customAmount', {
          toAmount: (amount * unitToSatoshi).toFixed(0),
          toAddress: $scope.toAddress
        });
      } else {
        $state.transitionTo('tabs.send.confirm', {
          recipientType: $scope.recipientType,
          toAmount: (amount * unitToSatoshi).toFixed(0),
          toAddress: $scope.toAddress,
          toName: $scope.toName,
          toEmail: $scope.toEmail,
          toColor: $scope.toColor,
        });
      }
    }
  };
});
<commit_msg>Fix alternativeIsoCode<commit_after>'use strict';

angular.module('copayApp.controllers').controller('amountController', function($scope, $filter, $timeout, $ionicScrollDelegate, $ionicHistory, gettextCatalog, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, txFormatService, ongoingProcess, popupService, bwcError, payproService, profileService, bitcore, amazonService) {
  var _cardId;
  var unitToSatoshi;
  var satToUnit;
  var unitDecimals;
  var satToBtc;
  var SMALL_FONT_SIZE_LIMIT = 10;
  var LENGTH_EXPRESSION_LIMIT = 19;
  $scope.isChromeApp = platformInfo.isChromeApp;

  $scope.$on('$ionicView.leave', function() {
    angular.element($window).off('keydown');
  });

  $scope.$on("$ionicView.beforeEnter", function(event, data) {

    // Go to...
    _cardId = data.stateParams.id; // Optional (BitPay Card ID)
    $scope.nextStep = data.stateParams.nextStep;
    $scope.currency = data.stateParams.currency;
    $scope.forceCurrency = data.stateParams.forceCurrency;

    $scope.showMenu = $ionicHistory.backView() && $ionicHistory.backView().stateName == 'tabs.send';
    $scope.recipientType = data.stateParams.recipientType || null;
    $scope.toAddress = data.stateParams.toAddress;
    $scope.toName = data.stateParams.toName;
    $scope.toEmail = data.stateParams.toEmail;
    $scope.showAlternativeAmount = !!$scope.nextStep;
    $scope.toColor = data.stateParams.toColor;
    $scope.showSendMax = false;

    $scope.customAmount = data.stateParams.customAmount;

    if (!$scope.nextStep && !data.stateParams.toAddress) {
      $log.error('Bad params at amount')
      throw ('bad params');
    }

    var reNr = /^[1234567890\.]$/;
    var reOp = /^[\*\+\-\/]$/;

    var disableKeys = angular.element($window).on('keydown', function(e) {
      if (e.which === 8) { // you can add others here inside brackets.
        e.preventDefault();
        $scope.removeDigit();
      }

      if (e.key && e.key.match(reNr))
        $scope.pushDigit(e.key);

      else if (e.key && e.key.match(reOp))
        $scope.pushOperator(e.key);

      else if (e.key && e.key == 'Enter')
        $scope.finish();

      $timeout(function() {
        $scope.$apply();
      });
    });

    var config = configService.getSync().wallet.settings;
    $scope.unitName = config.unitName;
    if (data.stateParams.currency) {
      $scope.alternativeIsoCode = data.stateParams.currency;
    } else {
      $scope.alternativeIsoCode = config.alternativeIsoCode || 'USD';
    }
    $scope.specificAmount = $scope.specificAlternativeAmount = '';
    $scope.isCordova = platformInfo.isCordova;
    unitToSatoshi = config.unitToSatoshi;
    satToUnit = 1 / unitToSatoshi;
    satToBtc = 1 / 100000000;
    unitDecimals = config.unitDecimals;

    $scope.resetAmount();

    // in SAT ALWAYS
    if ($stateParams.toAmount) {
      $scope.amount = (($stateParams.toAmount) * satToUnit).toFixed(unitDecimals);
    }

    processAmount($scope.amount);

    $timeout(function() {
      $ionicScrollDelegate.resize();
    }, 10);
  });

  $scope.showSendMaxMenu = function() {
    $scope.showSendMax = true;
  };

  $scope.sendMax = function() {
    $scope.showSendMax = false;
    $state.transitionTo('tabs.send.confirm', {
      recipientType: $scope.recipientType,
      toAmount: null,
      toAddress: $scope.toAddress,
      toName: $scope.toName,
      toEmail: $scope.toEmail,
      toColor: $scope.toColor,
      useSendMax: true,
    });
  };

  $scope.toggleAlternative = function() {
    if ($scope.forceCurrency) return;
    $scope.showAlternativeAmount = !$scope.showAlternativeAmount;

    if ($scope.amount && isExpression($scope.amount)) {
      var amount = evaluate(format($scope.amount));
      $scope.globalResult = '= ' + processResult(amount);
    }
  };

  function checkFontSize() {
    if ($scope.amount && $scope.amount.length >= SMALL_FONT_SIZE_LIMIT) $scope.smallFont = true;
    else $scope.smallFont = false;
  };

  $scope.pushDigit = function(digit) {
    if ($scope.amount && $scope.amount.length >= LENGTH_EXPRESSION_LIMIT) return;
    if ($scope.amount.indexOf('.') > -1 && digit == '.') return;
    if ($scope.showAlternativeAmount && $scope.amount.indexOf('.') > -1 && $scope.amount[$scope.amount.indexOf('.') + 2]) return;

    $scope.amount = ($scope.amount + digit).replace('..', '.');
    checkFontSize();
    processAmount($scope.amount);
  };

  $scope.pushOperator = function(operator) {
    if (!$scope.amount || $scope.amount.length == 0) return;
    $scope.amount = _pushOperator($scope.amount);

    function _pushOperator(val) {
      if (!isOperator(lodash.last(val))) {
        return val + operator;
      } else {
        return val.slice(0, -1) + operator;
      }
    };
  };

  function isOperator(val) {
    var regex = /[\/\-\+\x\*]/;
    return regex.test(val);
  };

  function isExpression(val) {
    var regex = /^\.?\d+(\.?\d+)?([\/\-\+\*x]\d?\.?\d+)+$/;
    return regex.test(val);
  };

  $scope.removeDigit = function() {
    $scope.amount = $scope.amount.slice(0, -1);
    processAmount($scope.amount);
    checkFontSize();
  };

  $scope.resetAmount = function() {
    $scope.amount = $scope.alternativeResult = $scope.amountResult = $scope.globalResult = '';
    $scope.allowSend = false;
    checkFontSize();
  };

  function processAmount(val) {
    if (!val) {
      $scope.resetAmount();
      return;
    }

    var formatedValue = format(val);
    var result = evaluate(formatedValue);
    $scope.allowSend = lodash.isNumber(result) && +result > 0;
    if (lodash.isNumber(result)) {
      $scope.globalResult = isExpression(val) ? '= ' + processResult(result) : '';
      $scope.amountResult = $filter('formatFiatAmount')(toFiat(result));
      $scope.alternativeResult = txFormatService.formatAmount(fromFiat(result) * unitToSatoshi, true);
    }
  };

  function processResult(val) {
    if ($scope.showAlternativeAmount)
      return $filter('formatFiatAmount')(val);
    else
      return txFormatService.formatAmount(val.toFixed(unitDecimals) * unitToSatoshi, true);
  };

  function fromFiat(val) {
    return parseFloat((rateService.fromFiat(val, $scope.alternativeIsoCode) * satToUnit).toFixed(unitDecimals));
  };

  function toFiat(val) {
    return parseFloat((rateService.toFiat(val * unitToSatoshi, $scope.alternativeIsoCode)).toFixed(2));
  };

  function evaluate(val) {
    var result;
    try {
      result = $scope.$eval(val);
    } catch (e) {
      return 0;
    }
    if (!lodash.isFinite(result)) return 0;
    return result;
  };

  function format(val) {
    var result = val.toString();

    if (isOperator(lodash.last(val)))
      result = result.slice(0, -1);

    return result.replace('x', '*');
  };

  $scope.finish = function() {
    var _amount = evaluate(format($scope.amount));

    if ($scope.nextStep) {
      $state.transitionTo($scope.nextStep, {
        id: _cardId,
        amount: _amount,
        currency: $scope.showAlternativeAmount ? $scope.alternativeIsoCode : ''
      });
    } else {
      var amount = $scope.showAlternativeAmount ? fromFiat(_amount) : _amount;
      if ($scope.customAmount) {
        $state.transitionTo('tabs.receive.customAmount', {
          toAmount: (amount * unitToSatoshi).toFixed(0),
          toAddress: $scope.toAddress
        });
      } else {
        $state.transitionTo('tabs.send.confirm', {
          recipientType: $scope.recipientType,
          toAmount: (amount * unitToSatoshi).toFixed(0),
          toAddress: $scope.toAddress,
          toName: $scope.toName,
          toEmail: $scope.toEmail,
          toColor: $scope.toColor,
        });
      }
    }
  };
});
<|endoftext|>