<commit_before>// Great new taggable widget that requires jQuery UI to be loaded.
// Enhances an existing text field (progressive enhancement). See
// the README

function pkInlineTaggableWidget(selector, options)
{
	$(selector).each(function()
	{
		// Semi-global
		var typeaheadUrl = options['typeahead-url'];
		var tagsLabel = options['tags-label'];
		var popularTags = options['popular-tags'];
		var existingTags = {};
		var allTags = options['all-tags'];
		var commitSelector = options['commit-selector'];
		var commitEvent = options['commit-event'];

		if (typeof(tagsLabel) == 'undefined')
		{
			tagsLabel = "Existing Tags";
		};
		if (typeof(popularTags) == 'undefined')
		{
			popularTags = {};
		};
		if (typeof(allTags) == 'undefined')
		{
			allTags == {};
		};
		if (typeof(commitEvent) == 'undefined')
		{
			commitEvent = 'click';
		}

		// populate existingTags
		if ($(this).val().trim() != '')
		{
			var lp = $(this).val().split(',');
			for (x in lp)
			{
				existingTags[lp[x].trim()] = lp[x].trim();
			}
		}

		function makePopularLink(attributes, title, text)
		{
			var new_tag = $('');
			var new_link = $('');
			new_tag.html(""+text+"");
			new_tag.attr({ title: title }).addClass('a-tag a-popular');
			new_tag.prepend(new_link);
			new_link.text(title);
			new_link.attr(attributes);
			return new_tag;
		}

		function makeRemoveLink(attributes, title, text)
		{
			title = $.trim(title);

			var new_tag = $('');
			var new_link = $('');
			var tagTitle = title;

			if (typeof(allTags) != 'undefined')
			{
				if (typeof(allTags[title]) != 'undefined')
				{
					title = title + '(' + allTags[title] + ')';
				}
				else
				{
					title = title + '(0)';
				}
			}

			new_tag.html(""+title+"");
			new_tag.attr({ title: tagTitle }).addClass('a-tag');
			new_link.text('Remove Tag');
			new_link.attr(attributes);
			new_link.attr({ title: 'Remove' }).addClass('a-btn icon a-close-small no-label no-bg');
			new_link.prepend('');
			new_tag.append(new_link);
			return new_tag;
		}

		function trimExcessCommas(string)
		{
			string = string.replace(/(^,)|(, ?$)/g, '');
			string = string.replace(/(,,)|(, ,)/, ',');
			string = $.trim(string);

			return string;
		}

		// For multiple word typeahead we need some helpers

		function split( val ) {
			return val.split( /,\s*/ );
		}

		function extractLast( term ) {
			return split( term ).pop();
		}

		function multipleSelect(event, ui)
		{
			var terms = split( this.value );
			// remove the current input
			terms.pop();
			// add the selected item
			terms.push( ui.item.value );
			// add placeholder to get the comma-and-space at the end
			terms.push( "" );
			this.value = terms.join( ", " );
			return false;
		}

		function multipleFocus()
		{
			// prevent value inserted on focus
			return false;
		}

		function multipleSearch()
		{
			// custom minLength
			var term = extractLast( this.value );
			if ( term.length < 2 ) {
				return false;
			}
		}

		// We don't want to display popular tags that we're already using
		var unusedPopulars = {};
		for (x in popularTags)
		{
			if (typeof(existingTags[x]) == 'undefined')
			{
				unusedPopulars[x] = popularTags[x];
			}
		}

		var popularsAttributes = {};
		var existingTagsAttributes = {};
		var existingDiv = $('
');
		var popularsDiv = $('
');

		// Establish the quick enhancement
		var tagInput = $(this);
		var typeAheadContainer = $('
');
		var typeAheadBox = $('<input />');
		var typeAheadBoxId = 'inline-tag-ahead-box-' + Math.floor(Math.random() * 2000);
		typeAheadBox.attr('type', 'text');
		typeAheadBox.attr('id', typeAheadBoxId);
		if ((typeof(allTags) == 'undefined') && (typeof(typeaheadUrl) != 'undefined'))
		{
			typeAheadBox.autocomplete({
			  source: function (request, response) {
					$.getJSON(typeaheadUrl, {
						  term: extractLast(request.term)
					  }, response);
				},
				search: multipleSearch,
				focus: multipleFocus,
				select: multipleSelect
			});
		}
		else if (typeof(allTags) != 'undefined')
		{
			var allTagsReformat = new Array();
			for (x in allTags)
			{
				allTagsReformat.push(x);
			}
			typeAheadBox.autocomplete({
				source: function (request, response) {
					response( $.ui.autocomplete.filter(
										allTagsReformat, extractLast( request.term ) ) );
				},
				search: multipleSearch,
				focus: multipleFocus,
				select: multipleSelect
			});
		}

		var addButton = $('');
		addButton.html('Add');
		addButton.attr({'href' : '#', 'class' : 'a-btn icon a-add add-tags-link', 'title' : 'Add these tags'});

		typeAheadContainer.addClass('a-inline-taggable-widget').append(typeAheadBox).append(addButton);

		tagInput.hide();
		tagInput.parent().append(typeAheadContainer);

		// Add a list of popular tags to be added
		function addTagsToForm(link)
		{
			var tag = link.attr('title');
			var value = tagInput.val() + ', ' + tag;

			value = trimExcessCommas(value);
			tagInput.val(value);

			link.remove();

			var new_link = makeRemoveLink(existingTagsAttributes, tag, tag + ' x');
			new_link.children('a').bind('click', function() { removeTagsFromForm($(this).parent()); return false; });
			existingDiv.append(new_link);
		}

		// Add a list of tags that may be removed
		function removeTagsFromForm(link)
		{
			var tag = link.attr('title');
			var value = tagInput.val();

			value = value.replace(tag, '');
			value = trimExcessCommas(value);
			tagInput.val(value);

			link.remove();

			// As we have just removed it from the list, we want the real deal populars.
			if (typeof(popularTags[tag]) != 'undefined')
			{
				var linkLabel = popularTags[tag];
				var new_link = makePopularLink(existingTagsAttributes, tag, linkLabel);
				new_link.children('a').bind('click', function() { addTagsToForm($(this).parent()); return false; });
				popularsDiv.append(new_link);
			}
		}

		// a maker function for tag containers
		function makeTagContainer(containerLabel, tagArray, linkAttributes, linkLabelType)
		{
			// Add a list of tags that may be removed
			var tagContainer = $('
');
			tagContainer.addClass('a-inline-taggable-widget-tag-container');
			var header = $('
');
			header.text(containerLabel);
			tagContainer.append(header);

			var attributes = {};
			for (x in tagArray)
			{
				var linkLabel = '';
				if (linkLabelType == 'add')
				{
					tagContainer.addClass('a-popular-tags');

					linkLabel = tagArray[x];
					var new_link = makePopularLink(linkAttributes, x, linkLabel);
					new_link.children('a').bind('click', function() { addTagsToForm($(this).parent());  return false; });
				}
				else if (linkLabelType == 'remove')
				{
					tagContainer.addClass('a-existing-tags');

					linkLabel = 'x ' + x;
					var new_link = makeRemoveLink(linkAttributes, x, linkLabel);
					new_link.children('a').bind('click', function() { removeTagsFromForm($(this).parent());  return false; });
				}
				tagContainer.append(new_link);
			}
			return tagContainer;
		}

		// Add the new tags to the existing form input.
		// If the user doesn't click Save changes or add... tough?
		function commitTagsToForm()
		{
			if (typeAheadBox.val() != '')
			{
				var value = tagInput.val() + ',' + typeAheadBox.val();
				value = trimExcessCommas(value);
				tagInput.val(value);
				typeAheadBox.val('');

				existingTags = {};
				var lp = value.split(',');
				for (x in lp)
				{
					existingTags[lp[x]] = lp[x];
				}

				existingDiv.html(makeTagContainer(tagsLabel, existingTags, existingTagsAttributes, 'remove').html());
				existingDiv.find('a').each(function() {
					$(this).bind('click', function() {
						removeTagsFromForm($(this).parent());
						return false;
					});
				});
			}
			return false;
		}
		addButton.bind('click', function() { commitTagsToForm(); return false; });
		if (commitSelector != 'undefined')
		{
			$(commitSelector).bind(commitEvent, function() {
				commitTagsToForm();
				return true;
			});
		}

		existingDiv = makeTagContainer(tagsLabel, existingTags, existingTagsAttributes, 'remove');
		existingDiv.children('a').bind('click', function() { removeTagsFromForm($(this));  return false; });
		tagInput.parent().prepend(existingDiv);

		popularsDiv = makeTagContainer('Popular Tags', unusedPopulars, popularsAttributes, 'add');
		popularsDiv.children('a').bind('click', function() { addTagsToForm($(this));  return false; });
		tagInput.parent().append(popularsDiv);

		// Catch that enter key, baby!
		$(document).keyup(function(e)
			{
				if (e.keyCode == 13)
				{
					e.preventDefault();
				}
			});

		$(document).keypress(function(e)
			{
				if (e.keyCode == 13)
				{
					e.preventDefault();
				}
			});

		typeAheadBox.keyup(function(e)
			{
		 		if (e.keyCode == 13)
		 		{
		 			commitTagsToForm();
		 		}
		 	});
	});

}

// DEPRECATED. Requires the old sfJqueryReloadedPlugin and generally is not as cool.

// You need to bring in jQuery first in order for this to work
//
// Call it like this:
// pkTagahead(<?php echo json_encode(url_for("taggableComplete/complete")) ?>);
//
// Or similar. Now all of your input elements with the input-tag class
// automatically gain the typeahead suggestion feature.
//
// If you're not using Symfony and sfDoctrineActAsTaggablePlugin,
// pass your own URL that returns a
 containing
s with the
// FULL TEXT of what the ENTIRE tag string will be if the user takes
// that suggestion, with the new tag you're suggesting an  link
// to #. Then use CSS to hide (visibility: none) the part of the
//
 that is not in the . Don't introduce any extra whitespace.

function pkTagahead(tagaheadUrl)
{
  $(function() {
    function getKey(event)
    {
      // Portable keycodes sigh
      return event.keyCode ? event.keyCode : event.which;
    }
    function setClick(target)
    {
      $(target).find('a').click(function(event)
      {
        // span contains ul contains li contains a
        var span = this.parentNode.parentNode.parentNode;
        var input = $(span).data("tag-peer");
        // Get text from the li
        var parent = this.parentNode;
        $(input).val($(parent).text());
        $(input).focus();
        return false;
      });
    }
    // Add suggestions span (you'll need to style that)
    $('input.tag-input').after("

");
    // Each tag field remembers its suggestions span...
    $('input.tag-input').each(function()
    {
      $(this).data("tag-peer", $(this).next()[0]);
    });
    // And vice versa
    $('div.tag-suggestions').each(function()
    {
      $(this).data("tag-peer", $(this).prev()[0]);
    });
    // Now we can really throw down
    $('input.tag-input').keyup(function(event)
    {
      var key = getKey(event);
      // Tab key
      if (key == 9)
      {
        var peer = $(this).data("tag-peer");
        var suggestions = $(peer).find("li");
        if (suggestions.length)
        {
          $(this).val($(suggestions[0]).text());
          $(this).focus();
        }
        // In any case don't insert the tab
        return false;
      }
      else
      {
        // Trigger ajax update of suggestions
      }
    });
    $('input.tag-input').keypress(function(event)
    {
      // Firefox 2.0 mac is stubborn and only allows cancel here
      // (we will still get the keyup and do the real work there)
      var key = getKey(event);
      if (key == 9)
      {
        // Don't insert tabs, ever
        return false;
      }
    });
    var lastValues = {};
    setInterval(function()
    {
      // AJAX query for suggestions only when changes have taken place
      $('input.tag-input').each(function()
      {
        var last = $(this).data('tag-last');
        var value = $(this).val();
        var peer = $(this).data('tag-peer');
        if (last !== value)
        {
          $(this).data('tag-last', value);
          $.post(
            tagaheadUrl,
            {
              current: $(this).val()
            },
            function(data, textStatus)
            {
              $(peer).html(data);
              setClick(peer);
            }
          );
        }
      });
    }, 200);
  });
}
<commit_msg>No labels for empty divs<commit_after>// Great new taggable widget that requires jQuery UI to be loaded.
// Enhances an existing text field (progressive enhancement). See
// the README

function pkInlineTaggableWidget(selector, options)
{
	$(selector).each(function()
	{
		// Semi-global
		var typeaheadUrl = options['typeahead-url'];
		var tagsLabel = options['tags-label'];
		var popularTags = options['popular-tags'];
		var existingTags = {};
		var allTags = options['all-tags'];
		var commitSelector = options['commit-selector'];
		var commitEvent = options['commit-event'];

		if (typeof(tagsLabel) == 'undefined')
		{
			tagsLabel = "Existing Tags";
		};
		if (typeof(popularTags) == 'undefined')
		{
			popularTags = {};
		};
		if (typeof(allTags) == 'undefined')
		{
			allTags == {};
		};
		if (typeof(commitEvent) == 'undefined')
		{
			commitEvent = 'click';
		}

		// populate existingTags
		if ($(this).val().trim() != '')
		{
			var lp = $(this).val().split(',');
			for (x in lp)
			{
				existingTags[lp[x].trim()] = lp[x].trim();
			}
		}

		function makePopularLink(attributes, title, text)
		{
			var new_tag = $('');
			var new_link = $('');
			new_tag.html(""+text+"");
			new_tag.attr({ title: title }).addClass('a-tag a-popular');
			new_tag.prepend(new_link);
			new_link.text(title);
			new_link.attr(attributes);
			return new_tag;
		}

		function makeRemoveLink(attributes, title, text)
		{
			title = $.trim(title);

			var new_tag = $('');
			var new_link = $('');
			var tagTitle = title;

			if (typeof(allTags) != 'undefined')
			{
				if (typeof(allTags[title]) != 'undefined')
				{
					title = title + '(' + allTags[title] + ')';
				}
				else
				{
					title = title + '(0)';
				}
			}

			new_tag.html(""+title+"");
			new_tag.attr({ title: tagTitle }).addClass('a-tag');
			new_link.text('Remove Tag');
			new_link.attr(attributes);
			new_link.attr({ title: 'Remove' }).addClass('a-btn icon a-close-small no-label no-bg');
			new_link.prepend('');
			new_tag.append(new_link);
			return new_tag;
		}

		function trimExcessCommas(string)
		{
			string = string.replace(/(^,)|(, ?$)/g, '');
			string = string.replace(/(,,)|(, ,)/, ',');
			string = $.trim(string);

			return string;
		}

		// For multiple word typeahead we need some helpers

		function split( val ) {
			return val.split( /,\s*/ );
		}

		function extractLast( term ) {
			return split( term ).pop();
		}

		function multipleSelect(event, ui)
		{
			var terms = split( this.value );
			// remove the current input
			terms.pop();
			// add the selected item
			terms.push( ui.item.value );
			// add placeholder to get the comma-and-space at the end
			terms.push( "" );
			this.value = terms.join( ", " );
			return false;
		}

		function multipleFocus()
		{
			// prevent value inserted on focus
			return false;
		}

		function multipleSearch()
		{
			// custom minLength
			var term = extractLast( this.value );
			if ( term.length < 2 ) {
				return false;
			}
		}

		// We don't want to display popular tags that we're already using
		var unusedPopulars = {};
		for (x in popularTags)
		{
			if (typeof(existingTags[x]) == 'undefined')
			{
				unusedPopulars[x] = popularTags[x];
			}
		}

		var popularsAttributes = {};
		var existingTagsAttributes = {};
		var existingDiv = $('
');
		var popularsDiv = $('
');

		// Establish the quick enhancement
		var tagInput = $(this);
		var typeAheadContainer = $('
');
		var typeAheadBox = $('<input />');
		var typeAheadBoxId = 'inline-tag-ahead-box-' + Math.floor(Math.random() * 2000);
		typeAheadBox.attr('type', 'text');
		typeAheadBox.attr('id', typeAheadBoxId);
		if ((typeof(allTags) == 'undefined') && (typeof(typeaheadUrl) != 'undefined'))
		{
			typeAheadBox.autocomplete({
			  source: function (request, response) {
					$.getJSON(typeaheadUrl, {
						  term: extractLast(request.term)
					  }, response);
				},
				search: multipleSearch,
				focus: multipleFocus,
				select: multipleSelect
			});
		}
		else if (typeof(allTags) != 'undefined')
		{
			var allTagsReformat = new Array();
			for (x in allTags)
			{
				allTagsReformat.push(x);
			}
			typeAheadBox.autocomplete({
				source: function (request, response) {
					response( $.ui.autocomplete.filter(
										allTagsReformat, extractLast( request.term ) ) );
				},
				search: multipleSearch,
				focus: multipleFocus,
				select: multipleSelect
			});
		}

		var addButton = $('');
		addButton.html('Add');
		addButton.attr({'href' : '#', 'class' : 'a-btn icon a-add add-tags-link', 'title' : 'Add these tags'});

		typeAheadContainer.addClass('a-inline-taggable-widget').append(typeAheadBox).append(addButton);

		tagInput.hide();
		tagInput.parent().append(typeAheadContainer);

		// Add a list of popular tags to be added
		function addTagsToForm(link)
		{
			var tag = link.attr('title');
			var value = tagInput.val() + ', ' + tag;

			value = trimExcessCommas(value);
			tagInput.val(value);

			if (link.parent().children().length == 2)
				link.parent().children('h4').hide();
			link.remove();

			var new_link = makeRemoveLink(existingTagsAttributes, tag, tag + ' x');
			new_link.children('a').bind('click', function() { removeTagsFromForm($(this).parent()); return false; });
			existingDiv.append(new_link);
			existingDiv.children('h4').show();
		}

		// Add a list of tags that may be removed
		function removeTagsFromForm(link)
		{
			var tag = link.attr('title');
			var value = tagInput.val();

			value = value.replace(tag, '');
			value = trimExcessCommas(value);
			tagInput.val(value);

			if (link.parent().children().length == 2)
				link.parent().children('h4').hide();
			link.remove();

			// As we have just removed it from the list, we want the real deal populars.
			if (typeof(popularTags[tag]) != 'undefined')
			{
				var linkLabel = popularTags[tag];
				var new_link = makePopularLink(existingTagsAttributes, tag, linkLabel);
				new_link.children('a').bind('click', function() { addTagsToForm($(this).parent()); return false; });
				popularsDiv.children('h4').show();
				popularsDiv.append(new_link);
			}
		}

		// a maker function for tag containers
		function makeTagContainer(containerLabel, tagArray, linkAttributes, linkLabelType)
		{
			// Add a list of tags that may be removed
			var tagContainer = $('
');
			tagContainer.addClass('a-inline-taggable-widget-tag-container');
			var header = $('
');
			header.text(containerLabel);
			tagContainer.append(header);

			if (objEmpty(tagArray))
			{
				header.hide();
			}

			var attributes = {};
			for (x in tagArray)
			{
				var linkLabel = '';
				if (linkLabelType == 'add')
				{
					tagContainer.addClass('a-popular-tags');

					linkLabel = tagArray[x];
					var new_link = makePopularLink(linkAttributes, x, linkLabel);
					new_link.children('a').bind('click', function() { addTagsToForm($(this).parent());  return false; });
				}
				else if (linkLabelType == 'remove')
				{
					tagContainer.addClass('a-existing-tags');

					linkLabel = 'x ' + x;
					var new_link = makeRemoveLink(linkAttributes, x, linkLabel);
					new_link.children('a').bind('click', function() { removeTagsFromForm($(this).parent());  return false; });
				}
				tagContainer.append(new_link);
			}
			return tagContainer;
		}

		// Add the new tags to the existing form input.
		// If the user doesn't click Save changes or add... tough?
		function commitTagsToForm()
		{
			if (typeAheadBox.val() != '')
			{
				var value = tagInput.val() + ',' + typeAheadBox.val();
				value = trimExcessCommas(value);
				tagInput.val(value);
				typeAheadBox.val('');

				existingTags = {};
				var lp = value.split(',');
				for (x in lp)
				{
					existingTags[lp[x]] = lp[x];
				}

				existingDiv.html(makeTagContainer(tagsLabel, existingTags, existingTagsAttributes, 'remove').html());
				existingDiv.find('a').each(function() {
					$(this).bind('click', function() {
						removeTagsFromForm($(this).parent());
						return false;
					});
				});
			}
			return false;
		}
		addButton.bind('click', function() { commitTagsToForm(); return false; });
		if (commitSelector != 'undefined')
		{
			$(commitSelector).bind(commitEvent, function() {
				commitTagsToForm();
				return true;
			});
		}

		existingDiv = makeTagContainer(tagsLabel, existingTags, existingTagsAttributes, 'remove');
		existingDiv.children('a').bind('click', function() { removeTagsFromForm($(this));  return false; });
		tagInput.parent().prepend(existingDiv);

		popularsDiv = makeTagContainer('Popular Tags', unusedPopulars, popularsAttributes, 'add');
		popularsDiv.children('a').bind('click', function() { addTagsToForm($(this));  return false; });
		tagInput.parent().append(popularsDiv);

		// Catch that enter key, baby!
		$(document).keyup(function(e)
			{
				if (e.keyCode == 13)
				{
					e.preventDefault();
				}
			});

		$(document).keypress(function(e)
			{
				if (e.keyCode == 13)
				{
					e.preventDefault();
				}
			});

		typeAheadBox.keyup(function(e)
			{
		 		if (e.keyCode == 13)
		 		{
		 			commitTagsToForm();
		 		}
		 	});

		function objEmpty(obj)
		{
			for (var prop in obj)
			{
				if (obj.hasOwnProperty(prop))
				{
					return false;
				}
			}

			return true;
		}
	});

}

// DEPRECATED. Requires the old sfJqueryReloadedPlugin and generally is not as cool.

// You need to bring in jQuery first in order for this to work
//
// Call it like this:
// pkTagahead(<?php echo json_encode(url_for("taggableComplete/complete")) ?>);
//
// Or similar. Now all of your input elements with the input-tag class
// automatically gain the typeahead suggestion feature.
//
// If you're not using Symfony and sfDoctrineActAsTaggablePlugin,
// pass your own URL that returns a
 containing
s with the
// FULL TEXT of what the ENTIRE tag string will be if the user takes
// that suggestion, with the new tag you're suggesting an  link
// to #. Then use CSS to hide (visibility: none) the part of the
//
 that is not in the . Don't introduce any extra whitespace.

function pkTagahead(tagaheadUrl)
{
  $(function() {
    function getKey(event)
    {
      // Portable keycodes sigh
      return event.keyCode ? event.keyCode : event.which;
    }
    function setClick(target)
    {
      $(target).find('a').click(function(event)
      {
        // span contains ul contains li contains a
        var span = this.parentNode.parentNode.parentNode;
        var input = $(span).data("tag-peer");
        // Get text from the li
        var parent = this.parentNode;
        $(input).val($(parent).text());
        $(input).focus();
        return false;
      });
    }
    // Add suggestions span (you'll need to style that)
    $('input.tag-input').after("

");
    // Each tag field remembers its suggestions span...
    $('input.tag-input').each(function()
    {
      $(this).data("tag-peer", $(this).next()[0]);
    });
    // And vice versa
    $('div.tag-suggestions').each(function()
    {
      $(this).data("tag-peer", $(this).prev()[0]);
    });
    // Now we can really throw down
    $('input.tag-input').keyup(function(event)
    {
      var key = getKey(event);
      // Tab key
      if (key == 9)
      {
        var peer = $(this).data("tag-peer");
        var suggestions = $(peer).find("li");
        if (suggestions.length)
        {
          $(this).val($(suggestions[0]).text());
          $(this).focus();
        }
        // In any case don't insert the tab
        return false;
      }
      else
      {
        // Trigger ajax update of suggestions
      }
    });
    $('input.tag-input').keypress(function(event)
    {
      // Firefox 2.0 mac is stubborn and only allows cancel here
      // (we will still get the keyup and do the real work there)
      var key = getKey(event);
      if (key == 9)
      {
        // Don't insert tabs, ever
        return false;
      }
    });
    var lastValues = {};
    setInterval(function()
    {
      // AJAX query for suggestions only when changes have taken place
      $('input.tag-input').each(function()
      {
        var last = $(this).data('tag-last');
        var value = $(this).val();
        var peer = $(this).data('tag-peer');
        if (last !== value)
        {
          $(this).data('tag-last', value);
          $.post(
            tagaheadUrl,
            {
              current: $(this).val()
            },
            function(data, textStatus)
            {
              $(peer).html(data);
              setClick(peer);
            }
          );
        }
      });
    }, 200);
  });
}
<|endoftext|>


<commit_before>/**
 *
 * Created by zhibo1 on 2014/12/15.
 */

var myApp;
myApp = myApp || (function () {
    var pleaseWaitDiv = $('
60% Complete
');
        return {
                showPleaseWait: function() {
                pleaseWaitDiv.modal();
            },
                hidePleaseWait: function () {
                pleaseWaitDiv.modal('hide');
            }
        };
    })();
/**
 *
 * @type {{pattern: RegExp, ret: string, statusCode: number, succMsg: string, alertMsg: string, jsonde: Function, trequest: Function, defau: Function, retOutput: Function, rawOutput: Function}}
 */
var handleObj = {
    pattern:/^(http|https):\/\//,
    ret:'',
    statusCode:0,
    succMsg:'Congratulations！',
    alertMsg:'Congratulations！',
    isRaw:1,
    /**
     * 文本是否需要服务器返回
     */
    contentPlace:function(){

    },
    /**
     * json解析
     * @returns {number}
     */
    jsonde: function() {
        if(this.pattern.exec(this.content))
        {
            this.trequest();
            this.rawOutput();
        }
        //格式化json文本
        Process();
        return 1;
    },
    serializede:function(){
        this.isRaw = 3;
        this.trequest();
        this.rawOutput();
        //格式化json文本
        Process();
        return 1;
    },
    trequest:function(){
        $.ajax({
            url: this.link,
            data:{text:this.content,side:this.sside,isRaw:this.isRaw},
            type:'POST',
            async:false,
            success: function(result){
                handleObj.ret = result;
            }
        });
    },
    defau: function(){
        //使用处理过的数据
        this.isRaw = 2;
        this.trequest();
        this.retOutput();
        return 1;
    },
    retOutput: function(){
        $('#Canvas').html(this.ret);
    },
    rawOutput: function(){
        $('#RawJson').val(this.ret);
    }
}
/**
 * submit code raw data by ajax
 * @param link action URL
 * @param sside action side: en/de
 * @param exec handle side
 */
function enclick(link,sside,execs)
{
    var a = $('.tab-content  .active').find('.content_holder');
    var content = a.val();
    if(!content)
    {
        alert('输入框不能为空！');
        return false;
    }
    //增加遮罩
    myApp.showPleaseWait();
    var cid = a.attr('id');
    //拼装对应函数名
    var mapHandle= execs + sside;
    if(!handleObj.hasOwnProperty(mapHandle))
    {
        mapHandle = 'defau';//
    }
    //传递提交变量
    handleObj.link = link;
    handleObj.content = content;
    handleObj.sside = sside;
    //执行方法
    var result = eval('handleObj.'+mapHandle+'()');
    //取消遮罩
    myApp.hidePleaseWait();
    //成功、错误提示
    var alert_id = (handleObj.statusCode !== 0) ? '#fail_result_output_alert' : '#success_result_output_alert';
    $(alert_id).css('display','block');
    $(alert_id).html(handleObj.alertMsg);
    element = $('#Canvas');
    offset = element.offset();
    offsetTop = offset.top - 125;
    $('html, body').animate({scrollTop: offsetTop}, 500, 'linear');
}
$(function(){

    $(document).on( 'scroll', function(){

        if ($(window).scrollTop() > 100) {
            $('.scroll-top-wrapper').addClass('show');
        } else {
            $('.scroll-top-wrapper').removeClass('show');
        }
    });

    $('.scroll-top-wrapper').on('click', scrollToTop);
});

function scrollToTop() {
    verticalOffset = typeof(verticalOffset) != 'undefined' ? verticalOffset : 0;
    element = $('body');
    offset = element.offset();
    offsetTop = offset.top;
    $('html, body').animate({scrollTop: offsetTop}, 500, 'linear');
}
/*json format raw js code from http://www.bodurov.com/JsonFormatter/*/
window.SINGLE_TAB = "  ";
window.ImgCollapsed = "images/Collapsed.gif";
window.ImgExpanded = "images/Expanded.gif";
window.QuoteKeys = true;
function $id(id){ return document.getElementById(id); }
function IsArray(obj) {
    return obj &&
        typeof obj === 'object' &&
        typeof obj.length === 'number' &&
        !(obj.propertyIsEnumerable('length'));
}
function Process(){
    SetTab();
    window.IsCollapsible = $id("CollapsibleView").checked;
    var json = $id("RawJson").value;
    var html = "";
    try{
        if(json == "") json = "\"\"";
        var obj = eval("["+json+"]");
        html = ProcessObject(obj[0], 0, false, false, false);
        $id("Canvas").innerHTML = "
"+html+"
";
    }catch(e){
        handleObj.alertMsg = "JSON is not well formated:\n"+e.message;
        handleObj.statusCode = -1;
        $id("Canvas").innerHTML = "";
    }
}
window._dateObj = new Date();
window._regexpObj = new RegExp();
function ProcessObject(obj, indent, addComma, isArray, isPropertyContent){
    var html = "";
    var comma = (addComma) ? ", " : "";
    var type = typeof obj;
    var clpsHtml ="";
    if(IsArray(obj)){
        if(obj.length == 0){
            html += GetRow(indent, "[ ]"+comma, isPropertyContent);
        }else{
            clpsHtml = window.IsCollapsible ? "" : "";
            html += GetRow(indent, "["+clpsHtml, isPropertyContent);
            for(var i = 0; i < obj.length; i++){
                html += ProcessObject(obj[i], indent + 1, i < (obj.length - 1), true, false);
            }
            clpsHtml = window.IsCollapsible ? "" : "";
            html += GetRow(indent, clpsHtml+"]"+comma);
        }
    }else if(type == 'object'){
        if (obj == null){
            html += FormatLiteral("null", "", comma, indent, isArray, "Null");
        }else if (obj.constructor == window._dateObj.constructor) {
            html += FormatLiteral("new Date(" + obj.getTime() + ") /*" + obj.toLocaleString()+"*/", "", comma, indent, isArray, "Date");
        }else if (obj.constructor == window._regexpObj.constructor) {
            html += FormatLiteral("new RegExp(" + obj + ")", "", comma, indent, isArray, "RegExp");
        }else{
            var numProps = 0;
            for(var prop in obj) numProps++;
            if(numProps == 0){
                html += GetRow(indent, "{ }"+comma, isPropertyContent);
            }else{
                clpsHtml = window.IsCollapsible ? "" : "";
                html += GetRow(indent, "{"+clpsHtml, isPropertyContent);
                var j = 0;
                for(var prop in obj){
                    var quote = window.QuoteKeys ? "\"" : "";
                    html += GetRow(indent + 1, ""+quote+prop+quote+": "+ProcessObject(obj[prop], indent + 1, ++j < numProps, false, true));
                }
                clpsHtml = window.IsCollapsible ? "" : "";
                html += GetRow(indent, clpsHtml+"}"+comma);
            }
        }
    }else if(type == 'number'){
        html += FormatLiteral(obj, "", comma, indent, isArray, "Number");
    }else if(type == 'boolean'){
        html += FormatLiteral(obj, "", comma, indent, isArray, "Boolean");
    }else if(type == 'function'){
        if (obj.constructor == window._regexpObj.constructor) {
            html += FormatLiteral("new RegExp(" + obj + ")", "", comma, indent, isArray, "RegExp");
        }else{
            obj = FormatFunction(indent, obj);
            html += FormatLiteral(obj, "", comma, indent, isArray, "Function");
        }
    }else if(type == 'undefined'){
        html += FormatLiteral("undefined", "", comma, indent, isArray, "Null");
    }else{
        html += FormatLiteral(obj.toString().split("\\").join("\\\\").split('"').join('\\"'), "\"", comma, indent, isArray, "String");
    }
    return html;
}
function FormatLiteral(literal, quote, comma, indent, isArray, style){
    if(typeof literal == 'string')
        literal = literal.split("<").join("<").split(">").join(">");
    var str = ""+quote+literal+quote+comma+"";
    if(isArray) str = GetRow(indent, str);
    return str;
}
function FormatFunction(indent, obj){
    var tabs = "";
    for(var i = 0; i < indent; i++) tabs += window.TAB;
    var funcStrArray = obj.toString().split("\n");
    var str = "";
    for(var i = 0; i < funcStrArray.length; i++){
        str += ((i==0)?"":tabs) + funcStrArray[i] + "\n";
    }
    return str;
}
function GetRow(indent, data, isPropertyContent){
    var tabs = "";
    for(var i = 0; i < indent && !isPropertyContent; i++) tabs += window.TAB;
    if(data != null && data.length > 0 && data.charAt(data.length-1) != "\n")
        data = data+"\n";
    return tabs+data;
}
function CollapsibleViewClicked(){
    $id("CollapsibleViewDetail").style.visibility = $id("CollapsibleView").checked ? "visible" : "hidden";
    Process();
}

function QuoteKeysClicked(){
    window.QuoteKeys = $id("QuoteKeys").checked;
    Process();
}

function CollapseAllClicked(){
    EnsureIsPopulated();
    TraverseChildren($id("Canvas"), function(element){
        if(element.className == 'collapsible'){
            MakeContentVisible(element, false);
        }
    }, 0);
}
function ExpandAllClicked(){
    EnsureIsPopulated();
    TraverseChildren($id("Canvas"), function(element){
        if(element.className == 'collapsible'){
            MakeContentVisible(element, true);
        }
    }, 0);
}
function MakeContentVisible(element, visible){
    var img = element.previousSibling.firstChild;
    if(!!img.tagName && img.tagName.toLowerCase() == "img"){
        element.style.display = visible ? 'inline' : 'none';
        element.previousSibling.firstChild.src = visible ? window.ImgExpanded : window.ImgCollapsed;
    }
}
function TraverseChildren(element, func, depth){
    for(var i = 0; i < element.childNodes.length; i++){
        TraverseChildren(element.childNodes[i], func, depth + 1);
    }
    func(element, depth);
}
function ExpImgClicked(img){
    var container = img.parentNode.nextSibling;
    if(!container) return;
    var disp = "none";
    var src = window.ImgCollapsed;
    if(container.style.display == "none"){
        disp = "inline";
        src = window.ImgExpanded;
    }
    container.style.display = disp;
    img.src = src;
}
function CollapseLevel(level){
    EnsureIsPopulated();
    TraverseChildren($id("Canvas"), function(element, depth){
        if(element.className == 'collapsible'){
            if(depth >= level){
                MakeContentVisible(element, false);
            }else{
                MakeContentVisible(element, true);
            }
        }
    }, 0);
}
function TabSizeChanged(){
    Process();
}
function SetTab(){
    var select = $id("TabSize");
    window.TAB = MultiplyString(parseInt(select.options[select.selectedIndex].value), window.SINGLE_TAB);
}
function EnsureIsPopulated(){
    if(!$id("Canvas").innerHTML && !!$id("RawJson").value) Process();
}
function MultiplyString(num, str){
    var sb =[];
    for(var i = 0; i < num; i++){
        sb.push(str);
    }
    return sb.join("");
}
function SelectAllClicked(){

    if(!!document.selection && !!document.selection.empty) {
        document.selection.empty();
    } else if(window.getSelection) {
        var sel = window.getSelection();
        if(sel.removeAllRanges) {
            window.getSelection().removeAllRanges();
        }
    }

    var range =
        (!!document.body && !!document.body.createTextRange)
            ? document.body.createTextRange()
            : document.createRange();

    if(!!range.selectNode)
        range.selectNode($id("Canvas"));
    else if(range.moveToElementText)
        range.moveToElementText($id("Canvas"));

    if(!!range.select)
        range.select($id("Canvas"));
    else
        window.getSelection().addRange(range);
}
function LinkToJson(){
    var val = $id("RawJson").value;
    val = escape(val.split('/n').join(' ').split('/r').join(' '));
    $id("InvisibleLinkUrl").value = val;
    $id("InvisibleLink").submit();
}

<commit_msg>ci Daily<commit_after>/**
 *
 * Created by zhibo1 on 2014/12/15.
 */

var myApp;
myApp = myApp || (function () {
    var pleaseWaitDiv = $('
60% Complete
');
        return {
                showPleaseWait: function() {
                pleaseWaitDiv.modal();
            },
                hidePleaseWait: function () {
                pleaseWaitDiv.modal('hide');
            }
        };
    })();
/**
 *
 * @type {{pattern: RegExp, ret: string, statusCode: number, succMsg: string, alertMsg: string, jsonde: Function, trequest: Function, defau: Function, retOutput: Function, rawOutput: Function}}
 */
var handleObj = {
    pattern:/^(http|https):\/\//,
    ret:'',
    statusCode:0,
    succMsg:'Congratulations！',
    alertMsg:'Congratulations！',
    isRaw:1,
    /**
     * 文本是否需要服务器返回
     */
    contentPlace:function(){

    },
    /**
     * json解析
     * @returns {number}
     */
    jsonde: function() {
        if(this.pattern.exec(this.content))
        {
            this.trequest();
            this.rawOutput();
        }
        //格式化json文本
        Process();
        return 1;
    },
    serializede:function(){
        this.isRaw = 3;
        this.trequest();
        this.rawOutput();
        //格式化json文本
        Process();
        return 1;
    },
    msgpackde:function(){
        this.isRaw = 3;
        this.trequest();
        this.rawOutput();
        //格式化json文本
        Process();
        return 1;
    },
    trequest:function(){
        $.ajax({
            url: this.link,
            data:{text:this.content,side:this.sside,isRaw:this.isRaw},
            type:'POST',
            async:false,
            success: function(result){
                handleObj.ret = result;
            }
        });
    },
    defau: function(){
        //使用处理过的数据
        this.isRaw = 2;
        this.trequest();
        this.retOutput();
        return 1;
    },
    retOutput: function(){
        $('#Canvas').html(this.ret);
    },
    rawOutput: function(){
        $('#RawJson').val(this.ret);
    }
}
/**
 * submit code raw data by ajax
 * @param link action URL
 * @param sside action side: en/de
 * @param exec handle side
 */
function enclick(link,sside,execs)
{
    var a = $('.tab-content  .active').find('.content_holder');
    var content = a.val();
    if(!content)
    {
        alert('输入框不能为空！');
        return false;
    }
    //增加遮罩
    myApp.showPleaseWait();
    var cid = a.attr('id');
    //拼装对应函数名
    var mapHandle= execs + sside;
    if(!handleObj.hasOwnProperty(mapHandle))
    {
        mapHandle = 'defau';//
    }
    //传递提交变量
    handleObj.link = link;
    handleObj.content = content;
    handleObj.sside = sside;
    //执行方法
    var result = eval('handleObj.'+mapHandle+'()');
    //取消遮罩
    myApp.hidePleaseWait();
    //成功、错误提示
    var alert_id = (handleObj.statusCode !== 0) ? '#fail_result_output_alert' : '#success_result_output_alert';
    $(alert_id).css('display','block');
    $(alert_id).html(handleObj.alertMsg);
    element = $('#Canvas');
    offset = element.offset();
    offsetTop = offset.top - 125;
    $('html, body').animate({scrollTop: offsetTop}, 500, 'linear');
}
$(function(){

    $(document).on( 'scroll', function(){

        if ($(window).scrollTop() > 100) {
            $('.scroll-top-wrapper').addClass('show');
        } else {
            $('.scroll-top-wrapper').removeClass('show');
        }
    });

    $('.scroll-top-wrapper').on('click', scrollToTop);
});

function scrollToTop() {
    verticalOffset = typeof(verticalOffset) != 'undefined' ? verticalOffset : 0;
    element = $('body');
    offset = element.offset();
    offsetTop = offset.top;
    $('html, body').animate({scrollTop: offsetTop}, 500, 'linear');
}
/*json format raw js code from http://www.bodurov.com/JsonFormatter/*/
window.SINGLE_TAB = "  ";
window.ImgCollapsed = "images/Collapsed.gif";
window.ImgExpanded = "images/Expanded.gif";
window.QuoteKeys = true;
function $id(id){ return document.getElementById(id); }
function IsArray(obj) {
    return obj &&
        typeof obj === 'object' &&
        typeof obj.length === 'number' &&
        !(obj.propertyIsEnumerable('length'));
}
function Process(){
    SetTab();
    window.IsCollapsible = $id("CollapsibleView").checked;
    var json = $id("RawJson").value;
    var html = "";
    try{
        if(json == "") json = "\"\"";
        var obj = eval("["+json+"]");
        html = ProcessObject(obj[0], 0, false, false, false);
        $id("Canvas").innerHTML = "
"+html+"
";
    }catch(e){
        handleObj.alertMsg = "JSON is not well formated:\n"+e.message;
        handleObj.statusCode = -1;
        $id("Canvas").innerHTML = "";
    }
}
window._dateObj = new Date();
window._regexpObj = new RegExp();
function ProcessObject(obj, indent, addComma, isArray, isPropertyContent){
    var html = "";
    var comma = (addComma) ? ", " : "";
    var type = typeof obj;
    var clpsHtml ="";
    if(IsArray(obj)){
        if(obj.length == 0){
            html += GetRow(indent, "[ ]"+comma, isPropertyContent);
        }else{
            clpsHtml = window.IsCollapsible ? "" : "";
            html += GetRow(indent, "["+clpsHtml, isPropertyContent);
            for(var i = 0; i < obj.length; i++){
                html += ProcessObject(obj[i], indent + 1, i < (obj.length - 1), true, false);
            }
            clpsHtml = window.IsCollapsible ? "" : "";
            html += GetRow(indent, clpsHtml+"]"+comma);
        }
    }else if(type == 'object'){
        if (obj == null){
            html += FormatLiteral("null", "", comma, indent, isArray, "Null");
        }else if (obj.constructor == window._dateObj.constructor) {
            html += FormatLiteral("new Date(" + obj.getTime() + ") /*" + obj.toLocaleString()+"*/", "", comma, indent, isArray, "Date");
        }else if (obj.constructor == window._regexpObj.constructor) {
            html += FormatLiteral("new RegExp(" + obj + ")", "", comma, indent, isArray, "RegExp");
        }else{
            var numProps = 0;
            for(var prop in obj) numProps++;
            if(numProps == 0){
                html += GetRow(indent, "{ }"+comma, isPropertyContent);
            }else{
                clpsHtml = window.IsCollapsible ? "" : "";
                html += GetRow(indent, "{"+clpsHtml, isPropertyContent);
                var j = 0;
                for(var prop in obj){
                    var quote = window.QuoteKeys ? "\"" : "";
                    html += GetRow(indent + 1, ""+quote+prop+quote+": "+ProcessObject(obj[prop], indent + 1, ++j < numProps, false, true));
                }
                clpsHtml = window.IsCollapsible ? "" : "";
                html += GetRow(indent, clpsHtml+"}"+comma);
            }
        }
    }else if(type == 'number'){
        html += FormatLiteral(obj, "", comma, indent, isArray, "Number");
    }else if(type == 'boolean'){
        html += FormatLiteral(obj, "", comma, indent, isArray, "Boolean");
    }else if(type == 'function'){
        if (obj.constructor == window._regexpObj.constructor) {
            html += FormatLiteral("new RegExp(" + obj + ")", "", comma, indent, isArray, "RegExp");
        }else{
            obj = FormatFunction(indent, obj);
            html += FormatLiteral(obj, "", comma, indent, isArray, "Function");
        }
    }else if(type == 'undefined'){
        html += FormatLiteral("undefined", "", comma, indent, isArray, "Null");
    }else{
        html += FormatLiteral(obj.toString().split("\\").join("\\\\").split('"').join('\\"'), "\"", comma, indent, isArray, "String");
    }
    return html;
}
function FormatLiteral(literal, quote, comma, indent, isArray, style){
    if(typeof literal == 'string')
        literal = literal.split("<").join("<").split(">").join(">");
    var str = ""+quote+literal+quote+comma+"";
    if(isArray) str = GetRow(indent, str);
    return str;
}
function FormatFunction(indent, obj){
    var tabs = "";
    for(var i = 0; i < indent; i++) tabs += window.TAB;
    var funcStrArray = obj.toString().split("\n");
    var str = "";
    for(var i = 0; i < funcStrArray.length; i++){
        str += ((i==0)?"":tabs) + funcStrArray[i] + "\n";
    }
    return str;
}
function GetRow(indent, data, isPropertyContent){
    var tabs = "";
    for(var i = 0; i < indent && !isPropertyContent; i++) tabs += window.TAB;
    if(data != null && data.length > 0 && data.charAt(data.length-1) != "\n")
        data = data+"\n";
    return tabs+data;
}
function CollapsibleViewClicked(){
    $id("CollapsibleViewDetail").style.visibility = $id("CollapsibleView").checked ? "visible" : "hidden";
    Process();
}

function QuoteKeysClicked(){
    window.QuoteKeys = $id("QuoteKeys").checked;
    Process();
}

function CollapseAllClicked(){
    EnsureIsPopulated();
    TraverseChildren($id("Canvas"), function(element){
        if(element.className == 'collapsible'){
            MakeContentVisible(element, false);
        }
    }, 0);
}
function ExpandAllClicked(){
    EnsureIsPopulated();
    TraverseChildren($id("Canvas"), function(element){
        if(element.className == 'collapsible'){
            MakeContentVisible(element, true);
        }
    }, 0);
}
function MakeContentVisible(element, visible){
    var img = element.previousSibling.firstChild;
    if(!!img.tagName && img.tagName.toLowerCase() == "img"){
        element.style.display = visible ? 'inline' : 'none';
        element.previousSibling.firstChild.src = visible ? window.ImgExpanded : window.ImgCollapsed;
    }
}
function TraverseChildren(element, func, depth){
    for(var i = 0; i < element.childNodes.length; i++){
        TraverseChildren(element.childNodes[i], func, depth + 1);
    }
    func(element, depth);
}
function ExpImgClicked(img){
    var container = img.parentNode.nextSibling;
    if(!container) return;
    var disp = "none";
    var src = window.ImgCollapsed;
    if(container.style.display == "none"){
        disp = "inline";
        src = window.ImgExpanded;
    }
    container.style.display = disp;
    img.src = src;
}
function CollapseLevel(level){
    EnsureIsPopulated();
    TraverseChildren($id("Canvas"), function(element, depth){
        if(element.className == 'collapsible'){
            if(depth >= level){
                MakeContentVisible(element, false);
            }else{
                MakeContentVisible(element, true);
            }
        }
    }, 0);
}
function TabSizeChanged(){
    Process();
}
function SetTab(){
    var select = $id("TabSize");
    window.TAB = MultiplyString(parseInt(select.options[select.selectedIndex].value), window.SINGLE_TAB);
}
function EnsureIsPopulated(){
    if(!$id("Canvas").innerHTML && !!$id("RawJson").value) Process();
}
function MultiplyString(num, str){
    var sb =[];
    for(var i = 0; i < num; i++){
        sb.push(str);
    }
    return sb.join("");
}
function SelectAllClicked(){

    if(!!document.selection && !!document.selection.empty) {
        document.selection.empty();
    } else if(window.getSelection) {
        var sel = window.getSelection();
        if(sel.removeAllRanges) {
            window.getSelection().removeAllRanges();
        }
    }

    var range =
        (!!document.body && !!document.body.createTextRange)
            ? document.body.createTextRange()
            : document.createRange();

    if(!!range.selectNode)
        range.selectNode($id("Canvas"));
    else if(range.moveToElementText)
        range.moveToElementText($id("Canvas"));

    if(!!range.select)
        range.select($id("Canvas"));
    else
        window.getSelection().addRange(range);
}
function LinkToJson(){
    var val = $id("RawJson").value;
    val = escape(val.split('/n').join(' ').split('/r').join(' '));
    $id("InvisibleLinkUrl").value = val;
    $id("InvisibleLink").submit();
}

<|endoftext|>


<commit_before>import Immutable from "immutable";
import R from "ramda";
import {allSensorsDecorator} from "lib/sensors-decorators";

const operatorMapping = {
    "+" : "add",
    "-" : "minus",
    "*" : "multiply",
    "/" : "divide",
    "(" : "open-braket",
    ")" : "close-braket",
    "^" : "circumflex",
    "sqrt" : "square-root",
    "TODO1" : "delta",
    "TODO2" : "add-1y",
    "TODO3" : "add-1m",
    "TODO4" : "add-1w",
    "TODO5" : "add-1d",
    "TODO6" : "add-15m",
    "TODO7" : "remove-1y",
    "TODO8" : "remove-1m",
    "TODO9" : "remove-1w",
    "TODO10" : "remove-1d",
    "TODO11" : "remove-15m"
};

export const potentialUnitsOfMeasurement = [
    {value: "cls", label: "Celsius"},
    {value: "far", label: "Fahrenheit"},
    {value: "wtt", label: "Watt"}
];

export function getUnitOfMeasurementLabel (val) {
    return R.find(R.propEq("value", val))(potentialUnitsOfMeasurement).label;
}

function swap (json) {
    var ret = {};
    for (var key in json) {
        ret[json[key]] = key;
    }
    return ret;
}

export const formulaToOperator = operatorMapping;
export const operatorToFormula = swap(operatorMapping);

export function findSensor (sensors, sensorId) {
    return sensors.get(sensorId);
}

export function getSensorLabel (sensor) {
    return sensor.get("name") ? sensor.get("name") : getSensorId(sensor);
}

export function getSensorId (sensor) {
    return sensor.get("_id") + "-" + sensor.get("measurementType");
}

//TODO capire se dev'essere ricorsiva....
export function extractSensorsFromFormula (formula, allSensors) {
    let sensorsIds = [];
    if (formula) {
        formula.split("|").forEach((item) => {
            if (!formulaToOperator[item]) {
                sensorsIds.push(allSensors.get(item));
            }
        });
    }
    return sensorsIds;
}

export function getAllSensors (sensorsCollection) {
    if (!sensorsCollection) {
        return Immutable.Map();
    }
    let originalToHide = [];
    sensorsCollection.forEach(sensor => {
        let parentId = sensor.get("parentSensorId");
        if (!sensor.get("isDeleted") && parentId) {
            originalToHide.push(parentId);
        }
    });
    return decorateWithMeasurementType(sensorsCollection.filter(
        sensor => !sensor.get("isDeleted") &&
        originalToHide.indexOf(sensor.get("_id")) < 0 &&
        sensor.get("type") !== "pod"
    ));
}

function decorateWithMeasurementType (sensors) {
    let items = {};
    let fakeTheme = {
        colors: {}
    };
    sensors.forEach(sensor => {
        let types = R.filter(R.propEq("type", sensor.get("type")))(allSensorsDecorator(fakeTheme));
        types.forEach(type => {
            let measurementType = type.key;
            let itemKey = sensor.get("_id") + "-" + measurementType;
            items[itemKey] = sensor.set("measurementType", measurementType);
        });
    });
    return Immutable.fromJS(items);
}<commit_msg>fix on clone and edit on monitoring<commit_after>import Immutable from "immutable";
import R from "ramda";
import {allSensorsDecorator} from "lib/sensors-decorators";

const operatorMapping = {
    "+" : "add",
    "-" : "minus",
    "*" : "multiply",
    "/" : "divide",
    "(" : "open-braket",
    ")" : "close-braket",
    "^" : "circumflex",
    "sqrt" : "square-root",
    "TODO1" : "delta",
    "TODO2" : "add-1y",
    "TODO3" : "add-1m",
    "TODO4" : "add-1w",
    "TODO5" : "add-1d",
    "TODO6" : "add-15m",
    "TODO7" : "remove-1y",
    "TODO8" : "remove-1m",
    "TODO9" : "remove-1w",
    "TODO10" : "remove-1d",
    "TODO11" : "remove-15m"
};

export const potentialUnitsOfMeasurement = [
    {value: "cls", label: "Celsius"},
    {value: "far", label: "Fahrenheit"},
    {value: "wtt", label: "Watt"}
];

export function getUnitOfMeasurementLabel (val) {
    return R.find(R.propEq("value", val))(potentialUnitsOfMeasurement).label;
}

function swap (json) {
    var ret = {};
    for (var key in json) {
        ret[json[key]] = key;
    }
    return ret;
}

export const formulaToOperator = operatorMapping;
export const operatorToFormula = swap(operatorMapping);

export function findSensor (sensors, sensorId) {
    return sensors.get(sensorId);
}

export function getSensorLabel (sensor) {
    return sensor.get("name") ? sensor.get("name") : getSensorId(sensor);
}

export function getSensorId (sensor) {
    return sensor.get("_id") + (sensor.get("measurementType") ? "-" + sensor.get("measurementType") : "");
}

//TODO capire se dev'essere ricorsiva....
export function extractSensorsFromFormula (formula, allSensors) {
    let sensorsIds = [];
    if (formula) {
        formula.split("|").forEach((item) => {
            if (!formulaToOperator[item]) {
                sensorsIds.push(allSensors.get(item));
            }
        });
    }
    return sensorsIds;
}

export function getAllSensors (sensorsCollection) {
    if (!sensorsCollection) {
        return Immutable.Map();
    }
    let originalToHide = [];
    sensorsCollection.forEach(sensor => {
        let parentId = sensor.get("parentSensorId");
        if (!sensor.get("isDeleted") && parentId) {
            originalToHide.push(parentId);
        }
    });
    return decorateWithMeasurementType(sensorsCollection.filter(
        sensor => !sensor.get("isDeleted") &&
        sensor.get("type") !== "pod"
    ), originalToHide);
}

function decorateWithMeasurementType (sensors, originalToHide) {
    let items = {};
    let fakeTheme = {
        colors: {}
    };
    sensors.forEach(sensor => {
        let types = R.filter(R.propEq("type", sensor.get("type")))(allSensorsDecorator(fakeTheme));
        if (types.length > 0) {
            types.forEach(type => {
                let measurementType = type.key;
                let itemKey = sensor.get("_id") + "-" + measurementType;
                if (originalToHide.indexOf(itemKey) < 0) {
                    items[itemKey] = sensor.set("measurementType", measurementType);
                }
            });
        } else {
            items[sensor.get("_id")] = sensor;
        }
    });
    return Immutable.fromJS(items);
}<|endoftext|>


<commit_before>function getValue(element)
{
    return element['value'];
}

function getNValuesAvg(values, idx, nb)
{
    vals = values.slice(idx, idx+nb).map(getValue);
    return {
        'date': values[idx]['date'],
        'value': d3.mean(vals)
    };

}

function getMovingAverages(values)
{
    var nb = 3;
    var results = new Array();
    var start = nb;
    for(var i=start;i<values.length+1;i++)
    {
        r = getNValuesAvg(values, i-start, nb);
        results.push(r);
    }
    return results;
}
function getData()
{
    return d3.range(33).map(d3.random.normal(10));
}

function getHistAvgValue(values)
{
    values.sort(d3.ascending);
    quart1 = d3.quantile(values, .25);
    quart3 = d3.quantile(values, .75);
    return (quart1+quart3)/2;
}

function sort_by_time(a, b) {
    return a.date < b.date ? -1 : a.date > b.date ? 1 : a.date >= b.date ? 0 : NaN;
};

function groupValuesByDate(values)
{
    var datas = {}, key;

    for(i in values)
    {
		key = Math.floor(values[i].date / 86400) * 86400;
        if(!datas[key])
        {
            datas[key] = [];
        }

        datas[key].push(values[i].value);
    }
    return datas;
}

function showBoxPlot(datas, div_id, date_from, date_to)
{
    // Define plot size and margins
    var height = 300;
    var width = 900;
    var margin_h = 30;
    var margin_w = 50;

    // Define the upper and lower whisker
    var data_percentile = .09;

    // create Date objects for xAxis domain
    date_from = new Date(date_from);
    date_to = new Date(date_to);

    // Interval between from and to
    var domain = d3.time.days(d3.time.day.offset(date_from, -1), date_to);

    // setup rangedata keys using the timestamp of the dates
    var rangedata = {};
    for(k in domain)
    {
        rangedata[ domain[k].getTime() ] = {'date': domain[k]};
    }

    // Setup rangedata entries with all the computer values for
    // plotting the boxes
    var values = d3.map(datas);

    // Create Date object for the whole data set
    var entries = values.entries();
    for(url in entries)
    {
        entries[url].value.sort(d3.ascending);

        var time = entries[url].key * 1000;
        var date = new Date(time);
        var key = time;
        // Set js timestamp and date object
        rangedata[key].time = time;
        //rangedata[date].date = date;
        rangedata[key].url = url;
        // Sort values
        rangedata[key].value = entries[url].value;
        // Mean
        rangedata[key].mean = d3.mean(rangedata[key].value);
        // Median
        rangedata[key].median = d3.median(rangedata[key].value);
        // Set first and third quartile
        rangedata[key].quart1 = d3.quantile(rangedata[key].value, .25);
        rangedata[key].quart3 = d3.quantile(rangedata[key].value, .75);
        // Midhinge
        rangedata[key].midhinge = (rangedata[key].quart3 + rangedata[key].quart1)/2;
        // IQR
        rangedata[key].iqr = rangedata[key].quart3 - rangedata[key].quart1;
        // Lower and upper fences
        //rangedata[key].lower = d3.quantile(rangedata[key].value, data_percentile);
        //rangedata[key].upper = d3.quantile(rangedata[key].value, 1-data_percentile);
        // Inner fences
        rangedata[key].lowerIn = d3.max(rangedata[key].quart1 - 1.5*rangedata[key].iqr, 0);
        rangedata[key].upperIn = d3.max(rangedata[key].quart3 + 1.5*rangedata[key].iqr, 0);
        // Outer fences
        rangedata[key].lowerOut = d3.max(rangedata[key].quart1 - 3*rangedata[key].iqr, 0);
        rangedata[key].upperOut = d3.max(rangedata[key].quart3 + 3*rangedata[key].iqr, 0);
        // trimean 20, 50 and 80

        // Store a value that is the maximum
        //rangedata[key].max = d3.max([rangedata[key].mean, rangedata[key].upperIn]);
        //rangedata[key].min = d3.min([rangedata[key].mean, rangedata[key].lowerIn]);
        rangedata[key].max = d3.max([rangedata[key].upperOut, rangedata[key].value]);
        rangedata[key].min = d3.min([rangedata[key].lowerOut, rangedata[key].value]);
    }

    // Change y domain values to have margins above and below min/max
    var margin_ud = 0.1;
    // Find global min and max of all distributions
    var min = d3.min(d3.values(rangedata).map(function(data){ return data.min;})) * (1-margin_ud) || 1;
    var max = d3.max(d3.values(rangedata).map(function(data){ return data.max;})) * (1+margin_ud) || 10;

    // y Axis
    var y = d3.scale.linear()
        .domain([max, min])
        .range([margin_h, height-margin_h]);

    // x Axis
    var x = d3.scale.ordinal()
        .domain(domain)
        .rangeRoundBands([margin_w, width-margin_w]);

    // Margin to the left and right of the boxes (in % of total width)
    var bin_margin_val = .2;

    // Store variables for sizes used to draw boxes
    var bin_width = x.rangeBand();
    var halfbin_width = bin_width/2;

    var bin_margin = bin_margin_val*bin_width;
    var halfbin_margin = bin_margin/2;

    var bar_width = bin_width-bin_margin;
    var halfbar_width = bar_width/2;

    // Create graph div and svg elements
    var div = d3.select(div_id)
        .append("div");

    var svg = div
        .append("svg")
        .attr("width", width)
        .attr("height", height);

    // Get ticks every X days
    var tickDays = domain.length > 10 ? 2 : 1;
    var ticks = domain.filter(function(d, i){ return i%tickDays==0;});

    // Show x axis
    var xAxis = d3.svg.axis()
        .scale(x)
        .orient("bottom")
        .tickValues(ticks)
        //.ticks(d3.time.days, 2)
        .tickFormat(d3.time.format("%d/%m"))
        .tickSize(6, 0);

    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + (height-margin_h) + ")")
        .call(xAxis);

    // Show y axis
    var yAxis = d3.svg.axis()
        .scale(y)
        .orient("left")
        //.ticks(5)
        .tickSize(4, 0);

    svg.append("g")
        .attr("class", "y axis")
        .attr("transform", "translate("+margin_w+",0)")
        .call(yAxis);

    // Adding grid lines
    svg.append("g")
        .attr("class", "grid")
        .attr("transform", "translate(0," + (margin_h) + ")")
        .call(xAxis
            .tickSize(height-(margin_h*2))
            .tickFormat("")
        );

    svg.append("g")
        .attr("class", "grid")
        .attr("transform", "translate("+margin_w+",0)")
        .call(yAxis
            .orient("right")
            .tickSize(width-(margin_w*2))
            .tickFormat("")
        );

    // Start drawing the data
    var bar = svg.selectAll(".bar")
        .data(d3.map(rangedata).values())
      .enter()
      ;
/*
    values.sort(sort_by_time);
    if(values.length > 3)
    {
        values = getMovingAverages(values);
    }
    values_key = values.map(function(d){return d.date;});
    values_val = values.map(function(d){return d.value;});

    bar.append("circle")
        .attr("cx", function(d,i){ return x(d.date)})
        .attr("cy", function(d,i){ return y(d.value)})
		.attr("r", 2)
        .attr("fill", "red")
        .append('svg:title')
        .text(function(d){return msformat(d.value)+'s';});

    bar.append("line")
        .attr("x1", function(d,i){ return x(d.date)})
        .attr("y1", function(d,i){ return y(d.value)})
        .attr("x2", function(d,i){ return values_key[i+1] ? x(values_key[i+1]) : x(d.date)})
        .attr("y2", function(d,i){ return values_val[i+1] ? y(values_val[i+1]) : y(d.value)})
        .attr("stroke", "green");
*/

        // Rectangle
        bar
        .append("g")

        .filter(function(d){ return d.value != null; })
        .append("rect")
        .attr("x", function(d, i){return x(d.date)+halfbin_margin;})
        .attr("y", function(d, i){
            if(!d.value)
                return 0;
            if(d.value.length == 1)
                return y(d.value[0]);
            return y(d.quart3);
            })
        .attr("width", bar_width)
        .attr("height", function(d, i){
            if(!d.value)
                return 0;
            if(d.value.length == 1)
                return 1;
            return y(d.quart1) - y(d.quart3)
        });

        // Bar up
        bar.append("g")
        .filter(function(d){ return d.value != null; })
        .append('line')
        .attr("x1", function(d,i){ return x(d.date)+halfbin_width})
        .attr("y1", function(d,i){ return y(d.upperIn)})
        .attr("x2", function(d,i){ return x(d.date)+halfbin_width})
        .attr("y2", function(d,i){ return y(d.quart3)})
        .attr("stroke", "black");

        // Upper whisker (inner fence)
        bar.append("g")
        .filter(function(d){ return d.value != null; })
        .append('line')
        .attr("x1", function(d,i){ return x(d.date)+halfbin_width-bar_width*.05;})
        .attr("y1", function(d,i){ return y(d.upperIn)})
        .attr("x2", function(d,i){ return x(d.date)+halfbin_width+bar_width*.05;})
        .attr("y2", function(d,i){ return y(d.upperIn)})
        .attr("stroke", "black");

        // Bar down
        bar.append("g")
        .filter(function(d){ return d.value != null; })
        .append('line')
        .attr("x1", function(d,i){ return x(d.date)+halfbin_width})
        .attr("y1", function(d,i){ return y(d.lowerIn)})
        .attr("x2", function(d,i){ return x(d.date)+halfbin_width})
        .attr("y2", function(d,i){ return y(d.quart1)})
        .attr("stroke", "black");

        // Lower whisker (inner fence)
        bar.append("g")
        .filter(function(d){ return d.value != null; })
        .append('line')
        .attr("x1", function(d,i){ return x(d.date)+halfbin_width-bar_width*.05;})
        .attr("y1", function(d,i){ return y(d.lowerIn)})
        .attr("x2", function(d,i){ return x(d.date)+halfbin_width+bar_width*.05;})
        .attr("y2", function(d,i){ return y(d.lowerIn)})
        .attr("stroke", "black");

        // Show outliners
        d3.map(rangedata).values().forEach(function(d){
            if(!d.value)
                return;
            svg.selectAll(".outline")
            .data(
                d.value.map(function(e){
                    return {
                        'date': d.date,
                        'val': e,
                        'lowerIn': d.lowerIn,
                        'upperIn': d.upperIn,
                        'lowerOut': d.lowerOut,
                        'upperOut': d.upperOut
                    };
                })
                .filter(function(d){
                    return d.val > d.upperIn || d.val < d.lowerIn;
                })
                // Limit number of outliners to plot, just in case
                // we end up with thousands of points to draw
                .slice(0, 30)
            )
            .enter()
            // Lower Outer fence
            .append("circle")
            .attr("cx", function(d,i){ return x(d.date)+halfbin_width})
            .attr("cy", function(d,i){ return y(d.val)})
            .attr("r", 2)
            .attr("stroke", "black")
            .attr("stroke-width", "1px")
            .attr("fill", "black")
            .filter(function(d){
                return d.val < d.upperOut || d.val > d.lowerOut;
            })
            .attr("fill", "none");
        });

        // Mean Dot
        bar.append("circle")
        .filter(function(d){ return d.value != null; })
        .attr("cx", function(d,i){ return x(d.date)+halfbin_width})
        .attr("cy", function(d,i){ return y(d.mean)})
		.attr("r", 2)
        .attr("fill", "red")
        .append('svg:title')
        .text(function(d){return d.mean;});

        // Mean Line
        bar.append("g")
        .filter(function(d){ return d.value != null; })
        .append('line')
        .attr("x1", function(d,i){ return x(d.date)+halfbin_width-bar_width*.05;})
        .attr("y1", function(d,i){ return y(d.mean)})
        .attr("x2", function(d,i){ return x(d.date)+halfbin_width+bar_width*.05;})
        .attr("y2", function(d,i){ return y(d.mean)})
        .attr("stroke", "red");

        // Median
        bar.append("g")
        .filter(function(d){ return d.value != null; })
        .append('line')
        .attr("x1", function(d,i){ return x(d.date)+halfbin_margin;})
        .attr("y1", function(d,i){ return y(d.median)})
        .attr("x2", function(d,i){ return x(d.date)+halfbin_margin+bar_width;})
        .attr("y2", function(d,i){ return y(d.median)})
        .attr("stroke", "blue");

}

<commit_msg>Fix call to d3.max<commit_after>function getValue(element)
{
    return element['value'];
}

function getNValuesAvg(values, idx, nb)
{
    vals = values.slice(idx, idx+nb).map(getValue);
    return {
        'date': values[idx]['date'],
        'value': d3.mean(vals)
    };

}

function getMovingAverages(values)
{
    var nb = 3;
    var results = new Array();
    var start = nb;
    for(var i=start;i<values.length+1;i++)
    {
        r = getNValuesAvg(values, i-start, nb);
        results.push(r);
    }
    return results;
}
function getData()
{
    return d3.range(33).map(d3.random.normal(10));
}

function getHistAvgValue(values)
{
    values.sort(d3.ascending);
    quart1 = d3.quantile(values, .25);
    quart3 = d3.quantile(values, .75);
    return (quart1+quart3)/2;
}

function sort_by_time(a, b) {
    return a.date < b.date ? -1 : a.date > b.date ? 1 : a.date >= b.date ? 0 : NaN;
};

function groupValuesByDate(values)
{
    var datas = {}, key;

    for(i in values)
    {
		key = Math.floor(values[i].date / 86400) * 86400;
        if(!datas[key])
        {
            datas[key] = [];
        }

        datas[key].push(values[i].value);
    }
    return datas;
}

function showBoxPlot(datas, div_id, date_from, date_to)
{
    // Define plot size and margins
    var height = 300;
    var width = 900;
    var margin_h = 30;
    var margin_w = 50;

    // Define the upper and lower whisker
    var data_percentile = .09;

    // create Date objects for xAxis domain
    date_from = new Date(date_from);
    date_to = new Date(date_to);

    // Interval between from and to
    var domain = d3.time.days(d3.time.day.offset(date_from, -1), date_to);

    // setup rangedata keys using the timestamp of the dates
    var rangedata = {};
    for(k in domain)
    {
        rangedata[ domain[k].getTime() ] = {'date': domain[k]};
    }

    // Setup rangedata entries with all the computer values for
    // plotting the boxes
    var values = d3.map(datas);

    // Create Date object for the whole data set
    var entries = values.entries();
    for(url in entries)
    {
        entries[url].value.sort(d3.ascending);

        var time = entries[url].key * 1000;
        var date = new Date(time);
        var key = time;
        // Set js timestamp and date object
        rangedata[key].time = time;
        //rangedata[date].date = date;
        rangedata[key].url = url;
        // Sort values
        rangedata[key].value = entries[url].value;
        // Mean
        rangedata[key].mean = d3.mean(rangedata[key].value);
        // Median
        rangedata[key].median = d3.median(rangedata[key].value);
        // Set first and third quartile
        rangedata[key].quart1 = d3.quantile(rangedata[key].value, .25);
        rangedata[key].quart3 = d3.quantile(rangedata[key].value, .75);
        // Midhinge
        rangedata[key].midhinge = (rangedata[key].quart3 + rangedata[key].quart1)/2;
        // IQR
        rangedata[key].iqr = rangedata[key].quart3 - rangedata[key].quart1;
        // Lower and upper fences
        //rangedata[key].lower = d3.quantile(rangedata[key].value, data_percentile);
        //rangedata[key].upper = d3.quantile(rangedata[key].value, 1-data_percentile);
        // Inner fences
        rangedata[key].lowerIn = d3.max([rangedata[key].quart1 - 1.5*rangedata[key].iqr, 0]);
        rangedata[key].upperIn = d3.max([rangedata[key].quart3 + 1.5*rangedata[key].iqr, 0]);
        // Outer fences
        rangedata[key].lowerOut = d3.max([rangedata[key].quart1 - 3*rangedata[key].iqr, 0]);
        rangedata[key].upperOut = d3.max([rangedata[key].quart3 + 3*rangedata[key].iqr, 0]);
        // trimean 20, 50 and 80

        // Store a value that is the maximum
        //rangedata[key].max = d3.max([rangedata[key].mean, rangedata[key].upperIn]);
        //rangedata[key].min = d3.min([rangedata[key].mean, rangedata[key].lowerIn]);
        rangedata[key].max = d3.max([rangedata[key].upperOut, rangedata[key].value]);
        rangedata[key].min = d3.min([rangedata[key].lowerOut, rangedata[key].value]);
    }

    // Change y domain values to have margins above and below min/max
    var margin_ud = 0.1;
    // Find global min and max of all distributions
    var min = d3.min(d3.values(rangedata).map(function(data){ return data.min;})) * (1-margin_ud) || 1;
    var max = d3.max(d3.values(rangedata).map(function(data){ return data.max;})) * (1+margin_ud) || 10;

    // y Axis
    var y = d3.scale.linear()
        .domain([max, min])
        .range([margin_h, height-margin_h]);

    // x Axis
    var x = d3.scale.ordinal()
        .domain(domain)
        .rangeRoundBands([margin_w, width-margin_w]);

    // Margin to the left and right of the boxes (in % of total width)
    var bin_margin_val = .2;

    // Store variables for sizes used to draw boxes
    var bin_width = x.rangeBand();
    var halfbin_width = bin_width/2;

    var bin_margin = bin_margin_val*bin_width;
    var halfbin_margin = bin_margin/2;

    var bar_width = bin_width-bin_margin;
    var halfbar_width = bar_width/2;

    // Create graph div and svg elements
    var div = d3.select(div_id)
        .append("div");

    var svg = div
        .append("svg")
        .attr("width", width)
        .attr("height", height);

    // Get ticks every X days
    var tickDays = domain.length > 10 ? 2 : 1;
    var ticks = domain.filter(function(d, i){ return i%tickDays==0;});

    // Show x axis
    var xAxis = d3.svg.axis()
        .scale(x)
        .orient("bottom")
        .tickValues(ticks)
        //.ticks(d3.time.days, 2)
        .tickFormat(d3.time.format("%d/%m"))
        .tickSize(6, 0);

    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + (height-margin_h) + ")")
        .call(xAxis);

    // Show y axis
    var yAxis = d3.svg.axis()
        .scale(y)
        .orient("left")
        //.ticks(5)
        .tickSize(4, 0);

    svg.append("g")
        .attr("class", "y axis")
        .attr("transform", "translate("+margin_w+",0)")
        .call(yAxis);

    // Adding grid lines
    svg.append("g")
        .attr("class", "grid")
        .attr("transform", "translate(0," + (margin_h) + ")")
        .call(xAxis
            .tickSize(height-(margin_h*2))
            .tickFormat("")
        );

    svg.append("g")
        .attr("class", "grid")
        .attr("transform", "translate("+margin_w+",0)")
        .call(yAxis
            .orient("right")
            .tickSize(width-(margin_w*2))
            .tickFormat("")
        );

    // Start drawing the data
    var bar = svg.selectAll(".bar")
        .data(d3.map(rangedata).values())
      .enter()
      ;
/*
    values.sort(sort_by_time);
    if(values.length > 3)
    {
        values = getMovingAverages(values);
    }
    values_key = values.map(function(d){return d.date;});
    values_val = values.map(function(d){return d.value;});

    bar.append("circle")
        .attr("cx", function(d,i){ return x(d.date)})
        .attr("cy", function(d,i){ return y(d.value)})
		.attr("r", 2)
        .attr("fill", "red")
        .append('svg:title')
        .text(function(d){return msformat(d.value)+'s';});

    bar.append("line")
        .attr("x1", function(d,i){ return x(d.date)})
        .attr("y1", function(d,i){ return y(d.value)})
        .attr("x2", function(d,i){ return values_key[i+1] ? x(values_key[i+1]) : x(d.date)})
        .attr("y2", function(d,i){ return values_val[i+1] ? y(values_val[i+1]) : y(d.value)})
        .attr("stroke", "green");
*/

        // Rectangle
        bar
        .append("g")

        .filter(function(d){ return d.value != null; })
        .append("rect")
        .attr("x", function(d, i){return x(d.date)+halfbin_margin;})
        .attr("y", function(d, i){
            if(!d.value)
                return 0;
            if(d.value.length == 1)
                return y(d.value[0]);
            return y(d.quart3);
            })
        .attr("width", bar_width)
        .attr("height", function(d, i){
            if(!d.value)
                return 0;
            if(d.value.length == 1)
                return 1;
            return y(d.quart1) - y(d.quart3)
        });

        // Bar up
        bar.append("g")
        .filter(function(d){ return d.value != null; })
        .append('line')
        .attr("x1", function(d,i){ return x(d.date)+halfbin_width})
        .attr("y1", function(d,i){ return y(d.upperIn)})
        .attr("x2", function(d,i){ return x(d.date)+halfbin_width})
        .attr("y2", function(d,i){ return y(d.quart3)})
        .attr("stroke", "black");

        // Upper whisker (inner fence)
        bar.append("g")
        .filter(function(d){ return d.value != null; })
        .append('line')
        .attr("x1", function(d,i){ return x(d.date)+halfbin_width-bar_width*.05;})
        .attr("y1", function(d,i){ return y(d.upperIn)})
        .attr("x2", function(d,i){ return x(d.date)+halfbin_width+bar_width*.05;})
        .attr("y2", function(d,i){ return y(d.upperIn)})
        .attr("stroke", "black");

        // Bar down
        bar.append("g")
        .filter(function(d){ return d.value != null; })
        .append('line')
        .attr("x1", function(d,i){ return x(d.date)+halfbin_width})
        .attr("y1", function(d,i){ return y(d.lowerIn)})
        .attr("x2", function(d,i){ return x(d.date)+halfbin_width})
        .attr("y2", function(d,i){ return y(d.quart1)})
        .attr("stroke", "black");

        // Lower whisker (inner fence)
        bar.append("g")
        .filter(function(d){ return d.value != null; })
        .append('line')
        .attr("x1", function(d,i){ return x(d.date)+halfbin_width-bar_width*.05;})
        .attr("y1", function(d,i){ return y(d.lowerIn)})
        .attr("x2", function(d,i){ return x(d.date)+halfbin_width+bar_width*.05;})
        .attr("y2", function(d,i){ return y(d.lowerIn)})
        .attr("stroke", "black");

        // Show outliners
        d3.map(rangedata).values().forEach(function(d){
            if(!d.value)
                return;
            svg.selectAll(".outline")
            .data(
                d.value.map(function(e){
                    return {
                        'date': d.date,
                        'val': e,
                        'lowerIn': d.lowerIn,
                        'upperIn': d.upperIn,
                        'lowerOut': d.lowerOut,
                        'upperOut': d.upperOut
                    };
                })
                .filter(function(d){
                    return d.val > d.upperIn || d.val < d.lowerIn;
                })
                // Limit number of outliners to plot, just in case
                // we end up with thousands of points to draw
                .slice(0, 30)
            )
            .enter()
            // Lower Outer fence
            .append("circle")
            .attr("cx", function(d,i){ return x(d.date)+halfbin_width})
            .attr("cy", function(d,i){ return y(d.val)})
            .attr("r", 2)
            .attr("stroke", "black")
            .attr("stroke-width", "1px")
            .attr("fill", "black")
            .filter(function(d){
                return d.val < d.upperOut || d.val > d.lowerOut;
            })
            .attr("fill", "none");
        });

        // Mean Dot
        bar.append("circle")
        .filter(function(d){ return d.value != null; })
        .attr("cx", function(d,i){ return x(d.date)+halfbin_width})
        .attr("cy", function(d,i){ return y(d.mean)})
		.attr("r", 2)
        .attr("fill", "red")
        .append('svg:title')
        .text(function(d){return d.mean;});

        // Mean Line
        bar.append("g")
        .filter(function(d){ return d.value != null; })
        .append('line')
        .attr("x1", function(d,i){ return x(d.date)+halfbin_width-bar_width*.05;})
        .attr("y1", function(d,i){ return y(d.mean)})
        .attr("x2", function(d,i){ return x(d.date)+halfbin_width+bar_width*.05;})
        .attr("y2", function(d,i){ return y(d.mean)})
        .attr("stroke", "red");

        // Median
        bar.append("g")
        .filter(function(d){ return d.value != null; })
        .append('line')
        .attr("x1", function(d,i){ return x(d.date)+halfbin_margin;})
        .attr("y1", function(d,i){ return y(d.median)})
        .attr("x2", function(d,i){ return x(d.date)+halfbin_margin+bar_width;})
        .attr("y2", function(d,i){ return y(d.median)})
        .attr("stroke", "blue");

}

<|endoftext|>