<commit_before>// add a notice encoded as JSON into the current timeline
//
// TODO: i18n

RealtimeUpdate = {
     _userid: 0,
     _replyurl: '',
     _favorurl: '',
     _deleteurl: '',

     init: function(userid, replyurl, favorurl, deleteurl)
     {
        RealtimeUpdate._userid = userid;
        RealtimeUpdate._replyurl = replyurl;
        RealtimeUpdate._favorurl = favorurl;
        RealtimeUpdate._deleteurl = deleteurl;
     },

     receive: function(data)
     {
          id = data.id;

          // Don't add it if it already exists
          //
          if ($("#notice-"+id).length > 0) {
               return;
          }

          var noticeItem = RealtimeUpdate.makeNoticeItem(data);
          $("#notices_primary .notices").prepend(noticeItem);
          $("#notices_primary .notice:first").css({display:"none"});
          $("#notices_primary .notice:first").fadeIn(1000);
          NoticeReply();
     },

     makeNoticeItem: function(data)
     {
          user = data['user'];
          html = data['html'].replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
          source = data['source'].replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');

          ni = "
"+
               "
"+
               ""+
               ""+
               ""+
               ""+user['screen_name']+""+
               ""+
               ""+
               "
"+html+"
"+
               "
"+
               "
"+
               ""+
               "a few seconds ago"+
               " "+
               ""+
               "from "+
                ""+source+""+ // may have a link
               "";
          if (data['in_reply_to_status_id']) {
               ni = ni+" in context";
          }

          ni = ni+"
"+
            "
";

          if (RealtimeUpdate._userid != 0) {
               var input = $("form#form_notice fieldset input#token");
               var session_key = input.val();
               ni = ni+RealtimeUpdate.makeFavoriteForm(data['id'], session_key);
               ni = ni+RealtimeUpdate.makeReplyLink(data['id'], data['user']['screen_name']);
               if (RealtimeUpdate._userid == data['user']['id']) {
                    ni = ni+RealtimeUpdate.makeDeleteLink(data['id']);
               }
          }

          ni = ni+"
"+
               "
";
          return ni;
     },

     makeFavoriteForm: function(id, session_key)
     {
          var ff;

          ff = "<form id=\"favor-"+id+"\" class=\"form_favor\" method=\"post\" action=\""+RealtimeUpdate._favorurl+"\">"+
                "<fieldset>"+
               "<legend>Favor this notice</legend>"+
               "<input name=\"token-"+id+"\" type=\"hidden\" id=\"token-"+id+"\" value=\""+session_key+"\"/>"+
               "<input name=\"notice\" type=\"hidden\" id=\"notice-n"+id+"\" value=\""+id+"\"/>"+
               "<input type=\"submit\" id=\"favor-submit-"+id+"\" name=\"favor-submit-"+id+"\" class=\"submit\" value=\"Favor\" title=\"Favor this notice\"/>"+
                "</fieldset>"+
               "</form>";
          return ff;
     },

     makeReplyLink: function(id, nickname)
     {
          var rl;
          rl = "Reply "+id+"";
          return rl;
        },

     makeDeleteLink: function(id)
     {
          var dl, delurl;
          delurl = RealtimeUpdate._deleteurl.replace("0000000000", id);

          dl = "Delete";

          return dl;
     },

     addPopup: function(url, timeline, iconurl)
     {
         $('#content').prepend('<button id="realtime_timeline" title="Realtime window">Realtime</button>');

         $('#realtime_timeline').css({
             'margin':'0 0 18px 0',
             'background':'transparent url('+ iconurl + ') no-repeat 0% 30%',
             'padding':'0 0 0 20px',
             'display':'block',
             'float':'right',
             'border':'none',
             'cursor':'pointer',
             'color':$("a").css("color"),
             'font-weight':'bold',
             'font-size':'1em'
         });

         $('#realtime_timeline').click(function() {
             window.open(url,
                         timeline,
                         'toolbar=no,resizable=yes,scrollbars=yes,status=yes');

             return false;
         });
     },

     initPopupWindow: function()
     {
         window.resizeTo(500, 550);
         $('address').hide();
         $('#content').css({'width':'93.5%'});

         $('#form_notice').css({
            'margin':'18px 0 18px 1.795%',
         });

         $('#form_notice label[for=notice_data-text], h1').css({'display': 'none'});

         $('.notices li:first-child').css({'border-top':'none'});
     }
}

<commit_msg>Aligning notice_data-attach from top<commit_after>// add a notice encoded as JSON into the current timeline
//
// TODO: i18n

RealtimeUpdate = {
     _userid: 0,
     _replyurl: '',
     _favorurl: '',
     _deleteurl: '',

     init: function(userid, replyurl, favorurl, deleteurl)
     {
        RealtimeUpdate._userid = userid;
        RealtimeUpdate._replyurl = replyurl;
        RealtimeUpdate._favorurl = favorurl;
        RealtimeUpdate._deleteurl = deleteurl;
     },

     receive: function(data)
     {
          id = data.id;

          // Don't add it if it already exists
          //
          if ($("#notice-"+id).length > 0) {
               return;
          }

          var noticeItem = RealtimeUpdate.makeNoticeItem(data);
          $("#notices_primary .notices").prepend(noticeItem);
          $("#notices_primary .notice:first").css({display:"none"});
          $("#notices_primary .notice:first").fadeIn(1000);
          NoticeReply();
     },

     makeNoticeItem: function(data)
     {
          user = data['user'];
          html = data['html'].replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
          source = data['source'].replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');

          ni = "
"+
               "
"+
               ""+
               ""+
               ""+
               ""+user['screen_name']+""+
               ""+
               ""+
               "
"+html+"
"+
               "
"+
               "
"+
               ""+
               "a few seconds ago"+
               " "+
               ""+
               "from "+
                ""+source+""+ // may have a link
               "";
          if (data['in_reply_to_status_id']) {
               ni = ni+" in context";
          }

          ni = ni+"
"+
            "
";

          if (RealtimeUpdate._userid != 0) {
               var input = $("form#form_notice fieldset input#token");
               var session_key = input.val();
               ni = ni+RealtimeUpdate.makeFavoriteForm(data['id'], session_key);
               ni = ni+RealtimeUpdate.makeReplyLink(data['id'], data['user']['screen_name']);
               if (RealtimeUpdate._userid == data['user']['id']) {
                    ni = ni+RealtimeUpdate.makeDeleteLink(data['id']);
               }
          }

          ni = ni+"
"+
               "
";
          return ni;
     },

     makeFavoriteForm: function(id, session_key)
     {
          var ff;

          ff = "<form id=\"favor-"+id+"\" class=\"form_favor\" method=\"post\" action=\""+RealtimeUpdate._favorurl+"\">"+
                "<fieldset>"+
               "<legend>Favor this notice</legend>"+
               "<input name=\"token-"+id+"\" type=\"hidden\" id=\"token-"+id+"\" value=\""+session_key+"\"/>"+
               "<input name=\"notice\" type=\"hidden\" id=\"notice-n"+id+"\" value=\""+id+"\"/>"+
               "<input type=\"submit\" id=\"favor-submit-"+id+"\" name=\"favor-submit-"+id+"\" class=\"submit\" value=\"Favor\" title=\"Favor this notice\"/>"+
                "</fieldset>"+
               "</form>";
          return ff;
     },

     makeReplyLink: function(id, nickname)
     {
          var rl;
          rl = "Reply "+id+"";
          return rl;
        },

     makeDeleteLink: function(id)
     {
          var dl, delurl;
          delurl = RealtimeUpdate._deleteurl.replace("0000000000", id);

          dl = "Delete";

          return dl;
     },

     addPopup: function(url, timeline, iconurl)
     {
         $('#content').prepend('<button id="realtime_timeline" title="Realtime window">Realtime</button>');

         $('#realtime_timeline').css({
             'margin':'0 0 18px 0',
             'background':'transparent url('+ iconurl + ') no-repeat 0% 30%',
             'padding':'0 0 0 20px',
             'display':'block',
             'float':'right',
             'border':'none',
             'cursor':'pointer',
             'color':$("a").css("color"),
             'font-weight':'bold',
             'font-size':'1em'
         });

         $('#realtime_timeline').click(function() {
             window.open(url,
                         timeline,
                         'toolbar=no,resizable=yes,scrollbars=yes,status=yes');

             return false;
         });
     },

     initPopupWindow: function()
     {
         window.resizeTo(500, 550);
         $('address').hide();
         $('#content').css({'width':'93.5%'});

         $('#form_notice').css({
            'margin':'18px 0 18px 1.795%',
         });

         $('#form_notice label[for=notice_data-text], h1').css({'display': 'none'});

         $('.notices li:first-child').css({'border-top':'none'});

         $('#form_notice label[for="notice_data-attach"], #form_notice #notice_data-attach').css({'top':'0'});
     }
}

<|endoftext|>


<commit_before>
import { Mixin, InitialRender } from './ce';
import { triggerEvent } from './events';
import { DisableBehavior } from './disabled';
import { FocusableBehavior } from './focus';

/**
 * Mixin that provides the behavior of a button. This set the role of the
 * element to `button`, add support for disabling it and normalize the
 * keyboard behavior.
 */
export let ButtonBehavior = Mixin(ParentClass => class extends ParentClass.with(DisableBehavior, FocusableBehavior, InitialRender) {
	initialRenderCallback() {
		super.initialRenderCallback();

		// Mark this element as a button
		this.setAttribute('role', 'button');

		/*
		 * Listener that listens for a key press of Enter or Space and
		 * emits a press event.
		 */
		this.addEventListener('keypress', e => {
			switch(e.code) {
				case 'Enter':
				case 'Space':
					e.preventDefault();
					if(! this.disabled) {
						triggerEvent(this, 'click');
					}
			}
		});
	}
});
<commit_msg>Use KeyboardEvent.key instead of code<commit_after>
import { Mixin, InitialRender } from './ce';
import { triggerEvent } from './events';
import { DisableBehavior } from './disabled';
import { FocusableBehavior } from './focus';

/**
 * Mixin that provides the behavior of a button. This set the role of the
 * element to `button`, add support for disabling it and normalize the
 * keyboard behavior.
 */
export let ButtonBehavior = Mixin(ParentClass => class extends ParentClass.with(DisableBehavior, FocusableBehavior, InitialRender) {
	initialRenderCallback() {
		super.initialRenderCallback();

		// Mark this element as a button
		this.setAttribute('role', 'button');

		/*
		 * Listener that listens for a key press of Enter or Space and
		 * emits a press event.
		 */
		this.addEventListener('keypress', e => {
			switch(e.key) {
				case 'Enter':
				case 'Space':
					e.preventDefault();
					if(! this.disabled) {
						triggerEvent(this, 'click');
					}
			}
		});
	}
});
<|endoftext|>


<commit_before>function initialize_events() {

  jQuery(document)
    .on('click', '.panel-heading span.clickable', function(e){
        jQuery(this).parents('.panel').find('.panel-collapse').collapse('toggle');
    })
    .on('show.bs.collapse', '.panel-collapse', function () {
        var $span = jQuery(this).parents('.panel').find('.panel-heading span.clickable');
        $span.find('i').removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-up');
    })
    .on('hide.bs.collapse', '.panel-collapse', function () {
        var $span = jQuery(this).parents('.panel').find('.panel-heading span.clickable');
        $span.find('i').removeClass('glyphicon-chevron-up').addClass('glyphicon-chevron-down');
    })

  //create_location_select_box();
  create_radio_button_options();

   jQuery('#submit').click( function() {
     var location = jQuery('#location_select').val();
     var start_date = jQuery('#daterange').data('daterangepicker').startDate.format('YYYY-MM-DD');
     var end_date = jQuery('#daterange').data('daterangepicker').endDate.format('YYYY-MM-DD');
     //var cap_types = jQuery('#types').val() || [];
     var types = jQuery('#types').val() || [];
     var typeNames = [];
     jQuery("#types > option").each(function(){
       typeNames.push(jQuery(this).text());
     });
     var nameHash = {};
     jQuery('#graphs_body').html("");
     for (var i = 0; i < types.length; i++) {
       nameHash[types[i]] = typeNames[i];
       jQuery('#graphs_body').append("

");
     }

     var interval = jQuery('#interval label.active input').val()

     var type_color = {
       temp: '#8C001A', //red
       day_length: '#FF9100', //orange
       intensity: '#ffd300', //yellow
       dp: '#5cb85c', //green
       rh: '#5bc0de', //light blue
       rain: '#428bca' //darker blue
     };

     var data = get_data(location, start_date, end_date, interval, type_color, types, nameHash);
   });
}

function get_data(location, start_date, end_date, interval, type_color, types, nameHash) {
  var spinner;
  jQuery.ajax( {
    url: '/rest/weather',
    data: { 'location' : location, 'start_date' : start_date, 'end_date' : end_date, 'interval' : interval, 'types' : types },
    beforeSend: function() {
      var target = document.getElementById('spinning_wheel');
      //console.log('target = '+target);
      spinner = new Spinner({color:'#ADD8E6', lines: 12}).spin(target);
      //jQuery('#working_msg').html('
 Testing the msg part of the working modal
');
      jQuery('#working_modal').modal("show");
    },
    success: function(response) {
	    if (response.error) {
        spinner.stop();
        jQuery('#working_modal').modal("hide");
        alert(response.error);
	    }
	    else {
        //console.log(JSON.stringify(response.raw_data));
        display_tables(response.stats, response.raw_data, response.values, response.metadata, location, start_date, end_date, interval);
        jQuery('a[data-toggle="tab"]').on( 'shown.bs.tab', function (e) {
          $.fn.dataTable.tables( {visible: true, api: true} ).columns.adjust();
        } );
        //console.log(JSON.stringify(response.stats));
        display_timeseries(response.values, response.metadata, response.stats, type_color, nameHash);
        spinner.stop();
        jQuery('#working_modal').modal("hide");
	    }
    },
    error: function(response) {
      spinner.stop();
      jQuery('#working_modal').modal("hide");
	    alert('error');
    }
  });
}

function select_all_options(obj) {
    if (!obj || obj.options.length ==0) { return; }
    for (var i=0; i<obj.options.length; i++) {
      obj.options[i].selected = true;
    }
    jQuery('#types').trigger('change');
}

function display_tables(summary_data, raw_data, values, metadata, location, start_date, end_date, interval) {
  jQuery('#table_panel').html('');
  var averages = " averages";
  if (interval == 'individual') { averages = " measurements";}
  var table_html = '

Summary

Raw Data

';
  table_html += '

 Table description: Summary of '+interval+averages+' from '+location+' between '+start_date+' and '+end_date+'.

';
  table_html += '

';
  table_html += 'Time	';
  var types= [];
  for (var type in values) {
    if (values.hasOwnProperty(type)) {
      types.push(type);
    }
  }
  types.sort ();
  for (i in types) {
    var type = types[i]
    var type_hash = metadata[type];
    table_html += ''+type_hash['description']+'	';
  }
  table_html += '

 Table description: All '+interval+averages+' from '+location+' between '+start_date+' and '+end_date+'.

';
  jQuery('#table_panel').html(table_html);
  var summary_table = jQuery('#summary_stats').DataTable( {
    dom: 'Bfrtip',
    buttons: ['copy', 'excel', 'csv', 'print' ],
    data: summary_data,
    destroy: true,
    paging: true,
    lengthMenu: [[10, 25, 50, -1], [10, 25, 50, "All"]],
    columns: [
      { title: "Data Type" },
      { title: "Unit" },
      { title: "Minimum" },
      { title: "Maximum" },
      { title: "Average" },
      { title: "Std Deviation" },
      { title: "Total Sum" },
      { title: "Location" },
      { title: "Start Date" },
      { title: "End Date" },
      { title: "Measurement Interval" }
    ],
    columnDefs: [
      { visible: false, targets: [7,8,9,10] }
    ]
  });
  var full_table = jQuery('#raw_data').DataTable( {
    dom: 'Bfrtip',
    buttons: ['copy', 'excel', 'csv', 'print' ],
    data: raw_data,
    destroy: true,
    paging: true,
    lengthMenu: [[10, 25, 50, -1], [10, 25, 50, "All"]]
  });
}

function display_timeseries(data, metadata, summary_data, type_color, nameHash) {
  for (var type in data) {
    if (data.hasOwnProperty(type)) {
      var type_hash = metadata[type];
      var max_y_value = get_max_y(type, summary_data, nameHash);
      var summary_array = summary_data[type];
      var averages = " averages in ";
      if (type_hash['interval'] == 'individual') { averages = " measurements in ";}
      var description = type_hash['interval'].capitalizeFirstLetter()+' '+type_hash['description'].toLowerCase()+averages+type_hash['unit']+', gathered by HOBO weather station at '+type_hash['location']+' betweeen '+type_hash['start_date']+' and '+type_hash['end_date']+'.';
      var converted_data = MG.convert.date(data[type], 'date', "%Y-%m-%d %H:%M:%S");
      MG.data_graphic({
        title: type_hash['description'],
        yax_units: type_hash['unit'],
        y_scale_type: 'linear',
        description: description,
        color: type_color[type],
        data: converted_data,
        interpolate: 'step',
        max_y: max_y_value,
    //  y_rug: true,
        linked: true,
        full_width: true,
        height: 300,
        right: 40,
        xax_count: 4,
        target: '#' + type
      });
    }
  }
}

function create_location_select_box() {
  jQuery.ajax( {
	url: '/rest/locations',
	success: function(response) {
      //console.log("locations= "+response);
      var select_html = '
Select a location:
<select class="form-control input-sm" id="location_select" autofocus="autofocus"><option></option><option>' + response.join('</option><option>') + '</option></select>';
      jQuery('#location_select_div').html(select_html);

      jQuery('#location_select').change(
         function() {
           var location = jQuery(this).val();
           create_type_multiple_select(location);
         }
       );
	},
	error: function(response) {
	    alert("An error occurred retrieving locations");
	}
    });
}

function create_radio_button_options() {
  var interval_html = '
Select measurement type:

<input type = "radio" name = "options" id = "option1" value="daily"> Daily averages<input type = "radio" name = "options" id = "option2" value="hourly"> Hourly averages<input type = "radio" name ="interval_options" id = "option3" value="individual">Individual values
'
  jQuery('#interval_select_div').html(interval_html);
  var type_html ='
Select data types:
<select multiple="" class="form-control disabled" id="types" name="1" style="min-width: 200px;overflow:auto;"></select>
<button class="btn btn-default btn-sm disabled" id="select_all" >Select All</button>';
  jQuery('#type_select_div').html(type_html);
  var daterange_html = '
Select a date range (defaults to full range available for the selected options):
<input class="form-control input-sm disabled" type="text" id="daterange" name="daterange"/>';
  jQuery('#daterange_select_div').html(daterange_html);
//  var time_html = '
Restrict by time of day:

<input type = "radio" name ="time_options" id = "both" value="both"> All measurements<input type = "radio" name = "time_options" id = "night" value="night"> Night only<input type = "radio" name = "time_options" id = "day" value="day"> Day only
'
//  jQuery('#time_select_div').html(time_html);
}

function create_type_multiple_select(location) {
  jQuery.ajax( {
	url: '/rest/types',
  data: {'location': location},
  success: function(response) {
      console.log("response types="+response.types);
      var locationTypes = response.types;
      jQuery('#types').html("");
      jQuery('#select_all').removeClass('disabled')
      var typesLength = response.types.length;
      jQuery('#select_all').removeClass('disabled');
      jQuery('#types').attr("size", typesLength);
      var type_html;
      for ( var i=0; i < typesLength; i++) {
        type_html += '<option value="'+response.types[i][0]+'">'+response.types[i][1]+'</option>';
      }
      jQuery('#types').append(type_html);
      jQuery('#select_all').click( function() {
          select_all_options(document.getElementById('types'));
      });
      jQuery('#types').change(
        function() {
          jQuery('#submit').removeClass('disabled');
          var location = jQuery('#location_select').val();
          var types = jQuery(this).val();
          create_daterangepicker(location,types);
      });
    },
  	error: function(response) {
  	    alert("An error occurred initializing type multiple select");
  	}
  });
}

String.prototype.capitalizeFirstLetter = function() {
    return this.charAt(0).toUpperCase() + this.slice(1);
}

function create_daterangepicker(location,types) {
  jQuery.ajax( {
  url: '/rest/dates',
  data: {'location': location, 'types': types},
  success: function(response) {

      var daterange_html = '
Select a date range (defaults to full range available for the selected options):
<input class="form-control input-sm" type="text" id="daterange" name="daterange"/>';
      jQuery('#daterange_select_div').html(daterange_html);
      var momentDate = moment(response.latest_date, 'YYYY-MM-DD');  // take max date and get date one month before
      var jsDate = momentDate.toDate();
      jsDate.setMonth(jsDate.getMonth() - 1);

      jQuery('input[name="daterange"]').daterangepicker(
        {
          locale: {
            format: 'YYYY-MM-DD'
          },
          "autoApply": true,
        //  "startDate": moment(jsDate).format('YYYY-MM-DD'),
          "startDate": response.earliest_date,
          "endDate": response.latest_date,
          "minDate": response.earliest_date,
          "maxDate": response.latest_date,
          "opens": "left"
        },
        function(start, end) {
          startDate = start.format('YYYY-MM-DD');
          endDate = end.format('YYYY-MM-DD');
        }
      );
    },
    error: function(response) {
        alert("An error occurred initializing daterangepicker");
    }
  });
}

function get_max_y(type, summary_data, nameHash) {
  var max;
  var full_name = nameHash[type];
  for (var i=0; i < summary_data.length; i++) {
    if (full_name == summary_data[i][0]) {
      max = summary_data[i][3];
    }
  }
  return max;
}
<commit_msg>build select box first<commit_after>function initialize_events() {

  jQuery(document)
    .on('click', '.panel-heading span.clickable', function(e){
        jQuery(this).parents('.panel').find('.panel-collapse').collapse('toggle');
    })
    .on('show.bs.collapse', '.panel-collapse', function () {
        var $span = jQuery(this).parents('.panel').find('.panel-heading span.clickable');
        $span.find('i').removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-up');
    })
    .on('hide.bs.collapse', '.panel-collapse', function () {
        var $span = jQuery(this).parents('.panel').find('.panel-heading span.clickable');
        $span.find('i').removeClass('glyphicon-chevron-up').addClass('glyphicon-chevron-down');
    })

  //create_location_select_box();
  create_radio_button_options();

   jQuery('#submit').click( function() {
     var location = jQuery('#location_select').val();
     var start_date = jQuery('#daterange').data('daterangepicker').startDate.format('YYYY-MM-DD');
     var end_date = jQuery('#daterange').data('daterangepicker').endDate.format('YYYY-MM-DD');
     //var cap_types = jQuery('#types').val() || [];
     var types = jQuery('#types').val() || [];
     var typeNames = [];
     jQuery("#types > option").each(function(){
       typeNames.push(jQuery(this).text());
     });
     var nameHash = {};
     jQuery('#graphs_body').html("");
     for (var i = 0; i < types.length; i++) {
       nameHash[types[i]] = typeNames[i];
       jQuery('#graphs_body').append("

");
     }

     var interval = jQuery('#interval label.active input').val()

     var type_color = {
       temp: '#8C001A', //red
       day_length: '#FF9100', //orange
       intensity: '#ffd300', //yellow
       dp: '#5cb85c', //green
       rh: '#5bc0de', //light blue
       rain: '#428bca' //darker blue
     };

     var data = get_data(location, start_date, end_date, interval, type_color, types, nameHash);
   });
}

function get_data(location, start_date, end_date, interval, type_color, types, nameHash) {
  var spinner;
  jQuery.ajax( {
    url: '/rest/weather',
    data: { 'location' : location, 'start_date' : start_date, 'end_date' : end_date, 'interval' : interval, 'types' : types },
    beforeSend: function() {
      var target = document.getElementById('spinning_wheel');
      //console.log('target = '+target);
      spinner = new Spinner({color:'#ADD8E6', lines: 12}).spin(target);
      //jQuery('#working_msg').html('
 Testing the msg part of the working modal
');
      jQuery('#working_modal').modal("show");
    },
    success: function(response) {
	    if (response.error) {
        spinner.stop();
        jQuery('#working_modal').modal("hide");
        alert(response.error);
	    }
	    else {
        //console.log(JSON.stringify(response.raw_data));
        display_tables(response.stats, response.raw_data, response.values, response.metadata, location, start_date, end_date, interval);
        jQuery('a[data-toggle="tab"]').on( 'shown.bs.tab', function (e) {
          $.fn.dataTable.tables( {visible: true, api: true} ).columns.adjust();
        } );
        //console.log(JSON.stringify(response.stats));
        display_timeseries(response.values, response.metadata, response.stats, type_color, nameHash);
        spinner.stop();
        jQuery('#working_modal').modal("hide");
	    }
    },
    error: function(response) {
      spinner.stop();
      jQuery('#working_modal').modal("hide");
	    alert('error');
    }
  });
}

function select_all_options(obj) {
    if (!obj || obj.options.length ==0) { return; }
    for (var i=0; i<obj.options.length; i++) {
      obj.options[i].selected = true;
    }
    jQuery('#types').trigger('change');
}

function display_tables(summary_data, raw_data, values, metadata, location, start_date, end_date, interval) {
  jQuery('#table_panel').html('');
  var averages = " averages";
  if (interval == 'individual') { averages = " measurements";}
  var table_html = '

Summary

Raw Data

';
  table_html += '

 Table description: Summary of '+interval+averages+' from '+location+' between '+start_date+' and '+end_date+'.

';
  table_html += '

';
  table_html += 'Time	';
  var types= [];
  for (var type in values) {
    if (values.hasOwnProperty(type)) {
      types.push(type);
    }
  }
  types.sort ();
  for (i in types) {
    var type = types[i]
    var type_hash = metadata[type];
    table_html += ''+type_hash['description']+'	';
  }
  table_html += '

 Table description: All '+interval+averages+' from '+location+' between '+start_date+' and '+end_date+'.

';
  jQuery('#table_panel').html(table_html);
  var summary_table = jQuery('#summary_stats').DataTable( {
    dom: 'Bfrtip',
    buttons: ['copy', 'excel', 'csv', 'print' ],
    data: summary_data,
    destroy: true,
    paging: true,
    lengthMenu: [[10, 25, 50, -1], [10, 25, 50, "All"]],
    columns: [
      { title: "Data Type" },
      { title: "Unit" },
      { title: "Minimum" },
      { title: "Maximum" },
      { title: "Average" },
      { title: "Std Deviation" },
      { title: "Total Sum" },
      { title: "Location" },
      { title: "Start Date" },
      { title: "End Date" },
      { title: "Measurement Interval" }
    ],
    columnDefs: [
      { visible: false, targets: [7,8,9,10] }
    ]
  });
  var full_table = jQuery('#raw_data').DataTable( {
    dom: 'Bfrtip',
    buttons: ['copy', 'excel', 'csv', 'print' ],
    data: raw_data,
    destroy: true,
    paging: true,
    lengthMenu: [[10, 25, 50, -1], [10, 25, 50, "All"]]
  });
}

function display_timeseries(data, metadata, summary_data, type_color, nameHash) {
  for (var type in data) {
    if (data.hasOwnProperty(type)) {
      var type_hash = metadata[type];
      var max_y_value = get_max_y(type, summary_data, nameHash);
      var summary_array = summary_data[type];
      var averages = " averages in ";
      if (type_hash['interval'] == 'individual') { averages = " measurements in ";}
      var description = type_hash['interval'].capitalizeFirstLetter()+' '+type_hash['description'].toLowerCase()+averages+type_hash['unit']+', gathered by HOBO weather station at '+type_hash['location']+' betweeen '+type_hash['start_date']+' and '+type_hash['end_date']+'.';
      var converted_data = MG.convert.date(data[type], 'date', "%Y-%m-%d %H:%M:%S");
      MG.data_graphic({
        title: type_hash['description'],
        yax_units: type_hash['unit'],
        y_scale_type: 'linear',
        description: description,
        color: type_color[type],
        data: converted_data,
        interpolate: 'step',
        max_y: max_y_value,
    //  y_rug: true,
        linked: true,
        full_width: true,
        height: 300,
        right: 40,
        xax_count: 4,
        target: '#' + type
      });
    }
  }
}

function create_location_select_box() {
  jQuery.ajax( {
	url: '/rest/locations',
  async: false,
	success: function(response) {
      //console.log("locations= "+response);
      var select_html = '
Select a location:
<select class="form-control input-sm" id="location_select" autofocus="autofocus"><option></option><option>' + response.join('</option><option>') + '</option></select>';
      jQuery('#location_select_div').html(select_html);

      jQuery('#location_select').change(
         function() {
           var location = jQuery(this).val();
           create_type_multiple_select(location);
         }
       );
	},
	error: function(response) {
	    alert("An error occurred retrieving locations");
	}
    });
}

function create_radio_button_options() {
  var interval_html = '
Select measurement type:

<input type = "radio" name = "options" id = "option1" value="daily"> Daily averages<input type = "radio" name = "options" id = "option2" value="hourly"> Hourly averages<input type = "radio" name ="interval_options" id = "option3" value="individual">Individual values
'
  jQuery('#interval_select_div').html(interval_html);
  var type_html ='
Select data types:
<select multiple="" class="form-control disabled" id="types" name="1" style="min-width: 200px;overflow:auto;"></select>
<button class="btn btn-default btn-sm disabled" id="select_all" >Select All</button>';
  jQuery('#type_select_div').html(type_html);
  var daterange_html = '
Select a date range (defaults to full range available for the selected options):
<input class="form-control input-sm disabled" type="text" id="daterange" name="daterange"/>';
  jQuery('#daterange_select_div').html(daterange_html);
//  var time_html = '
Restrict by time of day:

<input type = "radio" name ="time_options" id = "both" value="both"> All measurements<input type = "radio" name = "time_options" id = "night" value="night"> Night only<input type = "radio" name = "time_options" id = "day" value="day"> Day only
'
//  jQuery('#time_select_div').html(time_html);
}

function create_type_multiple_select(location) {
  jQuery.ajax( {
	url: '/rest/types',
  data: {'location': location},
  success: function(response) {
      console.log("response types="+response.types);
      var locationTypes = response.types;
      jQuery('#types').html("");
      jQuery('#select_all').removeClass('disabled')
      var typesLength = response.types.length;
      jQuery('#select_all').removeClass('disabled');
      jQuery('#types').attr("size", typesLength);
      var type_html;
      for ( var i=0; i < typesLength; i++) {
        type_html += '<option value="'+response.types[i][0]+'">'+response.types[i][1]+'</option>';
      }
      jQuery('#types').append(type_html);
      jQuery('#select_all').click( function() {
          select_all_options(document.getElementById('types'));
      });
      jQuery('#types').change(
        function() {
          jQuery('#submit').removeClass('disabled');
          var location = jQuery('#location_select').val();
          var types = jQuery(this).val();
          create_daterangepicker(location,types);
      });
    },
  	error: function(response) {
  	    alert("An error occurred initializing type multiple select");
  	}
  });
}

String.prototype.capitalizeFirstLetter = function() {
    return this.charAt(0).toUpperCase() + this.slice(1);
}

function create_daterangepicker(location,types) {
  jQuery.ajax( {
  url: '/rest/dates',
  data: {'location': location, 'types': types},
  success: function(response) {

      var daterange_html = '
Select a date range (defaults to full range available for the selected options):
<input class="form-control input-sm" type="text" id="daterange" name="daterange"/>';
      jQuery('#daterange_select_div').html(daterange_html);
      var momentDate = moment(response.latest_date, 'YYYY-MM-DD');  // take max date and get date one month before
      var jsDate = momentDate.toDate();
      jsDate.setMonth(jsDate.getMonth() - 1);

      jQuery('input[name="daterange"]').daterangepicker(
        {
          locale: {
            format: 'YYYY-MM-DD'
          },
          "autoApply": true,
        //  "startDate": moment(jsDate).format('YYYY-MM-DD'),
          "startDate": response.earliest_date,
          "endDate": response.latest_date,
          "minDate": response.earliest_date,
          "maxDate": response.latest_date,
          "opens": "left"
        },
        function(start, end) {
          startDate = start.format('YYYY-MM-DD');
          endDate = end.format('YYYY-MM-DD');
        }
      );
    },
    error: function(response) {
        alert("An error occurred initializing daterangepicker");
    }
  });
}

function get_max_y(type, summary_data, nameHash) {
  var max;
  var full_name = nameHash[type];
  for (var i=0; i < summary_data.length; i++) {
    if (full_name == summary_data[i][0]) {
      max = summary_data[i][3];
    }
  }
  return max;
}
<|endoftext|>


<commit_before>var Promise    = require('bluebird');
var rekt       = require('rekt').rekt;
var Book       = requireLocal('models/book.js');
var Page       = requireLocal('models/page.js');
var Difference = requireLocal('models/difference.js');
var _          = require('lodash');
var verifyWord = requireLocal('utils/compare.js');

/** @type {INT} The number of passes before we reject the request. */
var PASSCOUNT = 8;
function updateDifferences(unfilteredDifferences) {

  // nine passes MAX
  // Seperate passes
  // discard the passes

  // verify the rest,
  // Field is fine but the default should be not pass.
  // remerge passes and write to db

  var uniqueDiffs = _.uniq(unfilteredDifferences, '_id');
  var filteredDiffs = _.map(uniqueDiffs, verifyWord);
  return Promise.settle(filteredDiffs)
    .then(function(results) {

      /*==========  This whole section should be pulled out.  ==========*/
      var passCount = 0;
      _.forEach(uniqueDiffs, function(diff) {
        if (diff.pass === true) {
          passCount++;
        }
      });

      if (passCount > PASSCOUNT) {
        console.log('Too many passes');
        throw new rekt.BadRequest('Too many passes');
      }

      if (unfilteredDifferences === 0) {
        throw new rekt.BadRequest('You must provide diffs');
      }
      /*==========  This whole section should be pulled out.  ==========*/
      var possibleDifferences = _.chain(results)
        .map(function(result) {
          if (result.isFulfilled() && result.value) {
            return result.value();
          } else {
            return false;
          }
        })
        .compact()
        .value();
      if (possibleDifferences.length < 1) {
        throw new rekt.BadRequest('All words possible spam.');
      }
      return possibleDifferences;

    })
    .each(function(possible) {
      return Difference.findByIdAsync(possible._id)
        .then(function(foundDifference) {
          if (!foundDifference) {
            throw new rekt.NotFound('Difference not found');
          } else {
            return foundDifference;
          }
        })
        .then(function(foundDifference) {
          var index = _.findIndex(foundDifference.tags, {
            text: possibleDifference.text
          });
          var newPasses = 0;
          if (possibleDifference.pass === true) {
            var prevPasses = foundDifference.passes;
            newPasses = prevPasses ? prevPasses + 1 || 0;
          }
          if (index > -1) {
            var oldWeight = foundDifference.tags[index].weight;
            var newWeight = foundDifference.tags[index].weight + 1;
            foundDifference.tags.set(index, {
              text: possibleDifference.text,
              weight: newWeight
            });
            foundDifference.passes =
            return foundDifference.saveAsync();
          } else {
            foundDifference.tags.push({
              text: possibleDifference.text,
              weight: 0
            });
            foundDifference.passes = newPasses;
            return foundDifference.saveAsync();
          }
        });
    })

  // /**
  //  * Run our verifying algorithm on the unfilteredDifferences provided to us
  //  * by the user.
  //  */
  // var filtedDiffs = _.map(unfilteredDifferences, verifyWord);

  // /**
  //  * Because the verifyWord function is Async we have to wait for all of them
  //  * to either reject or verify. Once they all finish processing we can act on
  //  * them.
  //  */
  // return Promise.settle(filtedDiffs)
  //   .then(function(results) {
  //     var possibleDifferences = _.chain(results)
  //       .map(function(result) {
  //         if (result.isFulfilled() && result.value) {
  //           return result.value();
  //         } else {
  //           return false;
  //         }
  //       })
  //       .compact()
  //       .value();

  //     if (possibleDifferences.length < 1) {
  //       throw new rekt.BadWord('All words possible spam.');
  //     }

  //     return possibleDifferences;

  //   })
  //   .each(function(possibleDifference) {
  //     return Difference.findByIdAsync(possibleDifference._id)
  //       .then(function(foundDifference) {
  //         if (!foundDifference) {
  //           throw new rekt.NotFound('Difference not found');
  //         } else {
  //           return foundDifference;
  //         }
  //       })
  //       .then(function(foundDifference) {
  //         // If the possibleDifference is marked as passible and the max
  //         var index = _.findIndex(foundDifference.tags, {
  //           text: possibleDifference.text
  //         });
  //         if (index > -1) {
  //           var oldWeight = foundDifference.tags[index].weight;
  //           var newWeight = foundDifference.tags[index].weight + 1;
  //           foundDifference.tags.set(index, {
  //             text: possibleDifference.text,
  //             weight: newWeight
  //           });
  //           return foundDifference.saveAsync();
  //         } else {
  //           foundDifference.tags.push({
  //             text: possibleDifference.text,
  //             weight: 0
  //           });
  //           return foundDifference.saveAsync();
  //         }
  //       });
  //   });
}

module.exports = function(router) {
  router.route('/difference')
    .put(function(req, res) {
      var differences = req.body.differences;
      updateDifferences(differences)
        .then(function() {
          res.status(201);
          res.json({
            message: 'Differences updated'
          });
        })
        .catch(function(err) {
          console.log(err);
          res.send(err);
        });
    });
};
<commit_msg>testing diffs<commit_after>var Promise    = require('bluebird');
var rekt       = require('rekt').rekt;
var Book       = requireLocal('models/book.js');
var Page       = requireLocal('models/page.js');
var Difference = requireLocal('models/difference.js');
var _          = require('lodash');
var verifyWord = requireLocal('utils/compare.js');

/** @type {INT} The number of passes before we reject the request. */
var PASSCOUNT = 8;
function updateDifferences(unfilteredDifferences) {

  // nine passes MAX
  // Seperate passes
  // discard the passes

  // verify the rest,
  // Field is fine but the default should be not pass.
  // remerge passes and write to db

  var uniqueDiffs = _.uniq(unfilteredDifferences, '_id');
  var filteredDiffs = _.map(uniqueDiffs, verifyWord);
  return Promise.settle(filteredDiffs)
    .then(function(results) {

      /*==========  This whole section should be pulled out.  ==========*/
      var passCount = 0;
      _.forEach(uniqueDiffs, function(diff) {
        if (diff.pass === true) {
          passCount++;
        }
      });

      if (passCount > PASSCOUNT) {
        console.log('Too many passes');
        throw new rekt.BadRequest('Too many passes');
      }

      if (unfilteredDifferences === 0) {
        throw new rekt.BadRequest('You must provide diffs');
      }
      /*==========  This whole section should be pulled out.  ==========*/
      var possibleDifferences = _.chain(results)
        .map(function(result) {
          if (result.isFulfilled() && result.value) {
            return result.value();
          } else {
            return false;
          }
        })
        .compact()
        .value();
      if (possibleDifferences.length < 1) {
        throw new rekt.BadRequest('All words possible spam.');
      }
      return possibleDifferences;

    })
    .each(function(possible) {
      return Difference.findByIdAsync(possible._id)
        .then(function(foundDifference) {
          if (!foundDifference) {
            throw new rekt.NotFound('Difference not found');
          } else {
            return foundDifference;
          }
        })
        .then(function(foundDifference) {
          var index = _.findIndex(foundDifference.tags, {
            text: possibleDifference.text
          });
          var newPasses = 0;
          if (possibleDifference.pass === true) {
            var prevPasses = foundDifference.passes;
            newPasses = prevPasses ? prevPasses + 1 : 0;
          }
          if (index > -1) {
            var oldWeight = foundDifference.tags[index].weight;
            var newWeight = foundDifference.tags[index].weight + 1;
            foundDifference.tags.set(index, {
              text: possibleDifference.text,
              weight: newWeight
            });
            foundDifference.passes =
            return foundDifference.saveAsync();
          } else {
            foundDifference.tags.push({
              text: possibleDifference.text,
              weight: 0
            });
            foundDifference.passes = newPasses;
            return foundDifference.saveAsync();
          }
        });
    })

  // /**
  //  * Run our verifying algorithm on the unfilteredDifferences provided to us
  //  * by the user.
  //  */
  // var filtedDiffs = _.map(unfilteredDifferences, verifyWord);

  // /**
  //  * Because the verifyWord function is Async we have to wait for all of them
  //  * to either reject or verify. Once they all finish processing we can act on
  //  * them.
  //  */
  // return Promise.settle(filtedDiffs)
  //   .then(function(results) {
  //     var possibleDifferences = _.chain(results)
  //       .map(function(result) {
  //         if (result.isFulfilled() && result.value) {
  //           return result.value();
  //         } else {
  //           return false;
  //         }
  //       })
  //       .compact()
  //       .value();

  //     if (possibleDifferences.length < 1) {
  //       throw new rekt.BadWord('All words possible spam.');
  //     }

  //     return possibleDifferences;

  //   })
  //   .each(function(possibleDifference) {
  //     return Difference.findByIdAsync(possibleDifference._id)
  //       .then(function(foundDifference) {
  //         if (!foundDifference) {
  //           throw new rekt.NotFound('Difference not found');
  //         } else {
  //           return foundDifference;
  //         }
  //       })
  //       .then(function(foundDifference) {
  //         // If the possibleDifference is marked as passible and the max
  //         var index = _.findIndex(foundDifference.tags, {
  //           text: possibleDifference.text
  //         });
  //         if (index > -1) {
  //           var oldWeight = foundDifference.tags[index].weight;
  //           var newWeight = foundDifference.tags[index].weight + 1;
  //           foundDifference.tags.set(index, {
  //             text: possibleDifference.text,
  //             weight: newWeight
  //           });
  //           return foundDifference.saveAsync();
  //         } else {
  //           foundDifference.tags.push({
  //             text: possibleDifference.text,
  //             weight: 0
  //           });
  //           return foundDifference.saveAsync();
  //         }
  //       });
  //   });
}

module.exports = function(router) {
  router.route('/difference')
    .put(function(req, res) {
      var differences = req.body.differences;
      updateDifferences(differences)
        .then(function() {
          res.status(201);
          res.json({
            message: 'Differences updated'
          });
        })
        .catch(function(err) {
          console.log(err);
          res.send(err);
        });
    });
};
<|endoftext|>


<commit_before>const express = require('express');
const router = express.Router();
const util = require('util');

const query_sitters = "SELECT distinct uid, name, photo_url, location FROM babysitter";

const search_query = "SELECT distinct b.uid,b.name, b.photo_url, b.location from babysitter b left join schedule s on s.id_babysitter = b.id %s";

const connection = require('../../models/Connect');

router.get('/', isLoggedIn, function (req, res) {
    req.app.locals.searchName = "";
    req.app.locals.searchLocation = "";
    req.app.locals.searchPrice = "";
    req.app.locals.searchDate = "";
    req.app.locals.searchEvaluation = "";
    connection.query(query_sitters, function (err, result) {
        if (err) {
            res.send(err);
        } else {
            res.render('user/scheduling', {data: result});
        }
    });
});

router.post('/', isLoggedIn, function (req, res) {
    var name, location, priceMin, priceMax, date, evaluation, query, value;
    var combined = ' where ';
    if (req.body.name != "") {
        name = util.format("b.name like '%s' and ", "%" + req.body.name + "%");
        combined = combined.concat(name);
    }
    if (req.body.location != "") {
        location = util.format("b.location like '%s' and ", "%" + req.body.location + "%");
        combined = combined.concat(location);
    }
    if (req.body.priceMin != "") {
        priceMin = util.format("b.price >= '%s' and ", req.body.priceMin);
        combined = combined.concat(priceMin);
    }
    if (req.body.priceMax != "") {
        priceMax = util.format("b.price <= '%s' and ", req.body.priceMax);
        combined = combined.concat(priceMax);
    }
    if (req.body.date != "") {
        date = util.format("s.date = '%s' and ", req.body.date);
        combined = combined.concat(date);
    }
    if (req.body.evaluation != "" || req.app.locals.searchEvaluation != "") {
        if (req.body.evaluation != "") {
            value = req.body.evaluation;
        } else {
            value = req.app.locals.searchEvaluation;
        }
        evaluation = util.format("b.evaluation >= %s and ", value);
        combined = combined.concat(evaluation);
    }
    req.app.locals.searchName = req.body.name;

    req.app.locals.searchLocation = req.body.location;
    req.app.locals.searchPriceMin = req.body.priceMin;
    req.app.locals.searchPriceMax = req.body.priceMax;
    req.app.locals.searchDate = req.body.date;
    if (value != undefined) {
        req.app.locals.searchEvaluation = value;
    }
    if (combined != " where " ) {
        combined = combined.substring(0, combined.length - 5);
        query = util.format(search_query, combined);
    } else {
        query = query_sitters;
    }
    connection.query(query, function (err, result) {
        if (err) {
            res.send(err);
        } else {
            res.render('user/scheduling', {data: result});
        }
    });
});

function isLoggedIn(req, res, next) {
    if (req.app.locals.user) {
        return next();
    }
    res.redirect('/login');
}
module.exports = router;<commit_msg>added confirm buttons<commit_after>const express = require('express');
const router = express.Router();
const util = require('util');

const query_sitters = "SELECT distinct uid, name, photo_url, location FROM babysitter";

const search_query = "SELECT distinct b.uid,b.name, b.photo_url, b.location from babysitter b left join schedule s on s.id_babysitter = b.id %s";

const connection = require('../../models/Connect');

router.get('/', isLoggedIn, function (req, res) {
    req.app.locals.searchName = "";
    req.app.locals.searchLocation = "";
    req.app.locals.searchPrice = "";
    req.app.locals.searchDate = "";
    req.app.locals.searchEvaluation = "";
    connection.query(query_sitters, function (err, result) {
        if (err) {
            res.send(err);
        } else {
            res.render('user/scheduling', {data: result});
        }
    });
});

router.post('/', isLoggedIn, function (req, res) {
    var name, location, priceMin, priceMax, date, evaluation, query, value;
    var combined = ' where ';
    if (req.body.name != "") {
        name = util.format("b.name like '%s' and ", "%" + req.body.name + "%");
        combined = combined.concat(name);
    }
    if (req.body.location != "") {
        location = util.format("b.location like '%s' and ", "%" + req.body.location + "%");
        combined = combined.concat(location);
    }
    if (req.body.priceMin != "") {
        priceMin = util.format("b.price >= '%s' and ", req.body.priceMin);
        combined = combined.concat(priceMin);
    }
    if (req.body.priceMax != "") {
        priceMax = util.format("b.price <= '%s' and ", req.body.priceMax);
        combined = combined.concat(priceMax);
    }
    if (req.body.date != "") {
        date = util.format("s.date = '%s' and ", req.body.date);
        combined = combined.concat(date);
    }
    if (req.body.evaluation != "" || req.app.locals.searchEvaluation != "") {
        if (req.body.evaluation != "") {
            value = req.body.evaluation;
        } else {
            value = req.app.locals.searchEvaluation;
        }
        evaluation = util.format("b.evaluation >= %s and ", value);
        combined = combined.concat(evaluation);
    }
    req.app.locals.searchName = req.body.name;

    req.app.locals.searchLocation = req.body.location;
    req.app.locals.searchPriceMin = req.body.priceMin;
    req.app.locals.searchPriceMax = req.body.priceMax;
    req.app.locals.searchDate = req.body.date;
    if (value != undefined) {
        req.app.locals.searchEvaluation = value;
    }
    if (combined != " where " ) {
        combined = combined.substring(0, combined.length - 5);
        query = util.format(search_query, combined);
    } else {
        query = query_sitters;
    }
    connection.query(query, function (err, result) {
        if (err) {
            res.send(err);
        } else {
            res.render('user/scheduling', {data: result});
        }
    });
});

function isLoggedIn(req, res, next) {
    if (req.app.locals.user) {
        return next();
    }
    res.redirect('/login');
}
module.exports = router;<|endoftext|>


<commit_before>import Object from '@ember/object';
import THREE from "three";
import { shortenString } from '../helpers/string-helpers';
import { inject as service } from "@ember/service";

export default Object.extend({

  labels: null,
  textMaterialWhite: null,
  textMaterialBlack: null,

  session: service(),

  init() {
    this._super(...arguments);

    this.set('labels', []);
    this.set('textMaterialWhite',
      new THREE.MeshBasicMaterial({
        color: 0xffffff
      })
    );

    this.set('textMaterialBlack',
      new THREE.MeshBasicMaterial({
        color: 0x000000
      })
    );

    this.set('currentUser', this.get('session.session.content.authenticated.user'));
  },

  createLabel(parentMesh, parentObject, font, transparent) {
    const bBoxParent = new THREE.Box3().setFromObject(parentMesh);

    const worldParent = new THREE.Vector3();
    worldParent.setFromMatrixPosition(parentMesh.matrixWorld);

    const oldLabel = this.get('labels').filter(function (label) {
      const data = label.userData;

      return data.name === parentMesh.userData.name &&
        label.userData.parentPos.equals(worldParent);
    });

    // Check if TextGeometry already exists
    if (oldLabel && oldLabel[0]) {
      // Check if transparency changed, therefore requires an update
      if (transparent && !oldLabel[0].material.transparent) {
        const newMaterial = oldLabel[0].material.clone();
        newMaterial.transparent = true;
        newMaterial.opacity = this.get('currentUser.settings.numericAttributes.appVizTransparencyIntensity');
        oldLabel[0].material = newMaterial;
      }
      else if (!transparent && oldLabel[0].material.transparent) {
        const newMaterial = oldLabel[0].material.clone();
        newMaterial.transparent = false;
        newMaterial.opacity = 1.0;
        oldLabel[0].material = newMaterial;
      }

      parentObject.add(oldLabel[0]);
    }
    // New TextGeometry necessary
    else {
      let fontSize = 2;
      let labelString = parentMesh.userData.name;

      if (parentMesh.userData.type === 'clazz' && labelString.length > 10) {
        labelString = shortenString(labelString);
      }

      let textGeo = new THREE.TextGeometry(labelString, {
        font: font,
        size: fontSize,
        height: 0.1,
        curveSegments: 1
      });

      // Font color depending on parent object
      let material;
      if (parentMesh.userData.foundation) {
        material = this.get('textMaterialBlack').clone();
      }
      else if (parentMesh.userData.type === 'package') {
        material = this.get('textMaterialWhite').clone();
      }
      // Clazz
      else {
        material = this.get('textMaterialWhite').clone();
      }

      // Apply transparency / opacity
      if (transparent) {
        material.transparent = true;
        material.opacity = this.get('currentUser.settings.numericAttributes.appVizTransparencyIntensity');
      }

      let textMesh = new THREE.Mesh(textGeo, material);

      // Calculate textWidth
      textGeo.computeBoundingBox();
      let bBoxText = textGeo.boundingBox;
      let textBoxDimensions = new THREE.Vector3();
      bBoxText.getSize(textBoxDimensions);
      let textWidth = textBoxDimensions.x;

      // Calculate boundingbox of parent mesh
      let bBoxDimension = new THREE.Vector3();
      bBoxParent.getSize(bBoxDimension);
      let boxWidth = bBoxDimension.z;

      // Static size for class text
      let margin = 0.5;
      if (parentMesh.userData.type === 'clazz') {
        // Static scaling factor
        let scaleFactor = 0.3;
        textGeo.scale(scaleFactor, scaleFactor, scaleFactor);
      }
      // Handle text which is too big for a component
      else if (textWidth > (boxWidth - margin)) {
        // Compute factor to fit text to parent (including small margin)
        let scaleFactor = (boxWidth - margin) / textWidth;
        textGeo.scale(scaleFactor, scaleFactor, scaleFactor);

        // Update text width data
        textGeo.computeBoundingBox();
        bBoxText.getSize(textBoxDimensions);
        textWidth = textBoxDimensions.x;
      }

      // Calculate center for positioning
      textGeo.computeBoundingSphere();
      textGeo.center();
      let centerX = textGeo.boundingSphere.center.x;

      // Set position and rotation
      if (parentMesh.userData.opened) {
        textMesh.position.x = bBoxParent.min.x + 2;
        textMesh.position.y = bBoxParent.max.y;
        // Center mesh
        const centerTextBox = new THREE.Vector3();
        bBoxParent.getCenter(centerTextBox);
        textMesh.position.z = centerTextBox.z;
        textMesh.rotation.x = -(Math.PI / 2);
        textMesh.rotation.z = -(Math.PI / 2);
      }
      else {
        if (parentMesh.userData.type === 'clazz') {
          textMesh.position.x = worldParent.x - Math.abs(centerX) / 2 - 0.25;
          textMesh.position.y = bBoxParent.max.y;
          textMesh.position.z = (worldParent.z - Math
            .abs(centerX) / 2) - 0.25;
          textMesh.rotation.x = -(Math.PI / 2);
          textMesh.rotation.z = -(Math.PI / 3);
        } else {
          textMesh.position.x = worldParent.x - Math.abs(centerX) / 2;
          textMesh.position.y = bBoxParent.max.y;
          textMesh.position.z = worldParent.z - Math.abs(centerX) / 2;
          textMesh.rotation.x = -(Math.PI / 2);
          textMesh.rotation.z = -(Math.PI / 4);
        }
      }

      // Internal user-defined type
      textMesh.userData = {
        type: 'label',
        name: parentMesh.userData.name,
        parentPos: worldParent
      };

      // Add labels
      this.get('labels').push(textMesh);
      parentObject.add(textMesh);
    }
  }

});
<commit_msg>Center clazz labels and closed-component labels<commit_after>import Object from '@ember/object';
import THREE from "three";
import { shortenString } from '../helpers/string-helpers';
import { inject as service } from "@ember/service";

export default Object.extend({

  labels: null,
  textMaterialWhite: null,
  textMaterialBlack: null,

  session: service(),

  init() {
    this._super(...arguments);

    this.set('labels', []);
    this.set('textMaterialWhite',
      new THREE.MeshBasicMaterial({
        color: 0xffffff
      })
    );

    this.set('textMaterialBlack',
      new THREE.MeshBasicMaterial({
        color: 0x000000
      })
    );

    this.set('currentUser', this.get('session.session.content.authenticated.user'));
  },

  createLabel(parentMesh, parentObject, font, transparent) {
    const bBoxParent = new THREE.Box3().setFromObject(parentMesh);

    const worldParent = new THREE.Vector3();
    worldParent.setFromMatrixPosition(parentMesh.matrixWorld);

    const oldLabel = this.get('labels').filter(function (label) {
      const data = label.userData;

      return data.name === parentMesh.userData.name &&
        label.userData.parentPos.equals(worldParent);
    });

    // Check if TextGeometry already exists
    if (oldLabel && oldLabel[0]) {
      // Check if transparency changed, therefore requires an update
      if (transparent && !oldLabel[0].material.transparent) {
        const newMaterial = oldLabel[0].material.clone();
        newMaterial.transparent = true;
        newMaterial.opacity = this.get('currentUser.settings.numericAttributes.appVizTransparencyIntensity');
        oldLabel[0].material = newMaterial;
      }
      else if (!transparent && oldLabel[0].material.transparent) {
        const newMaterial = oldLabel[0].material.clone();
        newMaterial.transparent = false;
        newMaterial.opacity = 1.0;
        oldLabel[0].material = newMaterial;
      }

      parentObject.add(oldLabel[0]);
    }
    // New TextGeometry necessary
    else {
      let fontSize = 2;
      let labelString = parentMesh.userData.name;

      if (parentMesh.userData.type === 'clazz' && labelString.length > 10) {
        labelString = shortenString(labelString);
      }

      let textGeo = new THREE.TextGeometry(labelString, {
        font: font,
        size: fontSize,
        height: 0.1,
        curveSegments: 1
      });

      // Font color depending on parent object
      let material;
      if (parentMesh.userData.foundation) {
        material = this.get('textMaterialBlack').clone();
      }
      else if (parentMesh.userData.type === 'package') {
        material = this.get('textMaterialWhite').clone();
      }
      // Clazz
      else {
        material = this.get('textMaterialWhite').clone();
      }

      // Apply transparency / opacity
      if (transparent) {
        material.transparent = true;
        material.opacity = this.get('currentUser.settings.numericAttributes.appVizTransparencyIntensity');
      }

      let textMesh = new THREE.Mesh(textGeo, material);

      // Calculate textWidth
      textGeo.computeBoundingBox();
      let bBoxText = textGeo.boundingBox;
      let textBoxDimensions = new THREE.Vector3();
      bBoxText.getSize(textBoxDimensions);
      let textWidth = textBoxDimensions.x;

      // Calculate boundingbox of parent mesh
      let bBoxDimension = new THREE.Vector3();
      bBoxParent.getSize(bBoxDimension);
      let boxWidth = bBoxDimension.z;

      // Static size for class text
      let margin = 0.5;
      if (parentMesh.userData.type === 'clazz') {
        // Static scaling factor
        let scaleFactor = 0.3;
        textGeo.scale(scaleFactor, scaleFactor, scaleFactor);
      }
      // Handle text which is too big for a component
      else if (textWidth > (boxWidth - margin)) {
        // Compute factor to fit text to parent (including small margin)
        let scaleFactor = (boxWidth - margin) / textWidth;
        textGeo.scale(scaleFactor, scaleFactor, scaleFactor);

        // Update text width data
        textGeo.computeBoundingBox();
        bBoxText.getSize(textBoxDimensions);
        textWidth = textBoxDimensions.x;
      }

      // Calculate center for positioning
      textGeo.center();

      const centerParentBox = new THREE.Vector3();
      bBoxParent.getCenter(centerParentBox);

      // Set position and rotation
      if (parentMesh.userData.opened) {
        textMesh.position.x = bBoxParent.min.x + 2;
        textMesh.position.y = bBoxParent.max.y;
        // Center mesh
        textMesh.position.z = centerParentBox.z;
        textMesh.rotation.x = -(Math.PI / 2);
        textMesh.rotation.z = -(Math.PI / 2);
      } else {
        textMesh.position.x = centerParentBox.x;
        textMesh.position.y = bBoxParent.max.y;
        textMesh.position.z = centerParentBox.z;
        textMesh.rotation.x = -(Math.PI / 2);

        if (parentMesh.userData.type === 'clazz') {
          textMesh.rotation.z = -(Math.PI / 3);
        } else {
          textMesh.rotation.z = -(Math.PI / 4);
        }
      }

      // Internal user-defined type
      textMesh.userData = {
        type: 'label',
        name: parentMesh.userData.name,
        parentPos: worldParent
      };

      // Add labels
      this.get('labels').push(textMesh);
      parentObject.add(textMesh);
    }
  }

});
<|endoftext|>


<commit_before>dojo.provide("dojox.layout.ExpandoPane");
dojo.experimental("dojox.layout.ExpandoPane"); // just to show it can be done?

dojo.require("dijit.layout.ContentPane");
dojo.require("dijit._Templated");
dojo.require("dijit._Container");

dojo.declare("dojox.layout.ExpandoPane",
	[dijit.layout.ContentPane, dijit._Templated, dijit._Contained],
	{
	// summary: An experimental expando-pane for dijit.layout.BorderContainer
	//
	// description:
	//		Works just like a ContentPane inside of a borderContainer. Will expand/collapse on
	//		command, and supports having Layout Children as direct descendants
	//		via a custom "attachParent" attribute on the child.

	maxHeight: "",
	maxWidth: "",
	splitter: "",

	templatePath: dojo.moduleUrl("dojox.layout","resources/ExpandoPane.html"),

	_showing: true,

	// easeOut: String|Function
	//		easing function used to hide pane
	easeOut: "dojo._DefaultEasing",

	// easeIn: String|Function
	//		easing function use to show pane
	easeIn: "dojo._DefaultEasing",

	// duration: Integer
	//		duration to run show/hide animations
	duration: 420,

	startExpanded: true,

	"class": "dijitExpandoPane",

	postCreate: function(){

		this.inherited(arguments);
		this._animConnects = [];

		this._isHorizontal = true;

		if(dojo.isString(this.easeOut)){
			this.easeOut = dojo.getObject(this.easeOut);
		}
		if(dojo.isString(this.easeIn)){
			this.easeIn = dojo.getObject(this.easeIn);
		}

		var thisClass = "";
		if(this.region){
			// FIXME: add suport for alternate region types?
			switch(this.region){
				case "right" :
					thisClass = "Right";
					break;
				case "left" :
					thisClass = "Left";
					break;
				case "top" :
					thisClass = "Top";
					break;
				case "bottom" :
					thisClass = "Bottom";
					break;
			}
			dojo.addClass(this.domNode, "dojoxExpando" + thisClass);
			this._isHorizontal = /top|bottom/.test(this.region);
		}
		dojo.style(this.domNode, {
			overflow: "hidden",
			padding:0,
		});
	},

	startup: function(){
		this.inherited(arguments);

		this._container = this.getParent();
		this._closedSize = this._titleHeight = dojo.marginBox/*_getBorderBox*/(this.titleWrapper).h;

		if(this.splitter){
			// find our splitter and tie into it's drag logic
			var myid = this.id;
			dijit.registry.filter(function(w){
				return w && w.child && w.child.id == myid;
			}).forEach(dojo.hitch(this,function(w){
				this.connect(w,"_stopDrag","_afterResize");
			}));
		}

		this._currentSize = dojo.marginBox(this.domNode);
		this._showSize = this._currentSize[(this._isHorizontal ? "h" : "w")];
		this._setupAnims();

		if(this.startExpanded){
			this._showing = true;
		}else{
			this._hideWrapper();
			this._hideAnim.gotoPercent(99,true);
		}
	},

	_afterResize: function(e){
		var tmp = this._currentSize;
		this._currentSize = dojo.marginBox(this.domNode);
		var n = this._currentSize[(this._isHorizontal ? "h" : "w")]
		if(n > this._titleHeight){
			if(!this._showing){
				this._showing = !this._showing;
				this._showEnd();
			}
			this._showSize = n;
			this._setupAnims();
		}else{
			this._showSize = tmp[(this._isHorizontal ? "h" : "w")];
			this._showing = false;
			this._hideWrapper();
			this._hideAnim.gotoPercent(89,true);
		}

	},

	_setupAnims: function(){
		// summary: Create the show and hide animations
		dojo.forEach(this._animConnects, dojo.disconnect);

		var _common = {
			node:this.domNode,
			duration:this.duration
		};

		var isHorizontal = this._isHorizontal;
		var showProps = {};
		var hideProps = {};

		var dimension = isHorizontal ? "height" : "width";
		showProps[dimension] = {
			end: this._showSize,
			unit:"px"
		};
		hideProps[dimension] = {
			end: this._closedSize,
			unit:"px"
		};

		this._showAnim = dojo.animateProperty(dojo.mixin(_common,{
			easing:this.easeIn,
			properties: showProps
		}));
		this._hideAnim = dojo.animateProperty(dojo.mixin(_common,{
			easing:this.easeOut,
			properties: hideProps
		}));

		this._animConnects = [
			dojo.connect(this._showAnim,"onEnd",this,"_showEnd"),
			dojo.connect(this._hideAnim,"onEnd",this,"_hideEnd")
		];
	},

	toggle: function(){
		// summary: Toggle this pane's visibility
		if(this._showing){
			this._hideWrapper();
			this._showAnim && this._showAnim.stop();
			this._hideAnim.play();
		}else{
			this._hideAnim && this._hideAnim.stop();
			this._showAnim.play();
		}
		this._showing = !this._showing;
	},

	_hideWrapper: function(){
		// summary: Set the Expando state to "closed"
		dojo.addClass(this.domNode, "dojoxExpandoClosed");
		dojo.style(this.cwrapper,{
			visibility: "hidden",
			opacity: "0",
			overflow: "hidden"
		});
	},

	_showEnd: function(){
		// summary: Common animation onEnd code - "unclose"
		dojo.style(this.cwrapper, { opacity: 0, visibility:"visible" });
		dojo.fadeIn({ node:this.cwrapper, duration:227 }).play(1);
		dojo.removeClass(this.domNode, "dojoxExpandoClosed");
		setTimeout(dojo.hitch(this._container, "layout"), 15);
	},

	_hideEnd: function(){
		setTimeout(dojo.hitch(this._container, "layout"), 15);
	},

	resize: function(){
		// summary: we aren't a layout widget, but need to act like one:
		var size = dojo.marginBox(this.domNode),
			h = size.h - this._titleHeight;

		dojo.style(this.containerNode, "height", h + "px");
		this.inherited(arguments);
	},

	_trap: function(e){
		dojo.stopEvent(e);
	}

});
<commit_msg>fixes #7365 - stupid stray comma, my fault. Also change to use this.connect over dojo.connect(..,..,this !strict<commit_after>dojo.provide("dojox.layout.ExpandoPane");
dojo.experimental("dojox.layout.ExpandoPane"); // just to show it can be done?

dojo.require("dijit.layout.ContentPane");
dojo.require("dijit._Templated");
dojo.require("dijit._Container");

dojo.declare("dojox.layout.ExpandoPane",
	[dijit.layout.ContentPane, dijit._Templated, dijit._Contained],
	{
	// summary: An experimental expando-pane for dijit.layout.BorderContainer
	//
	// description:
	//		Works just like a ContentPane inside of a borderContainer. Will expand/collapse on
	//		command, and supports having Layout Children as direct descendants
	//		via a custom "attachParent" attribute on the child.

	maxHeight: "",
	maxWidth: "",
	splitter: "",

	templatePath: dojo.moduleUrl("dojox.layout","resources/ExpandoPane.html"),

	_showing: true,

	// easeOut: String|Function
	//		easing function used to hide pane
	easeOut: "dojo._DefaultEasing",

	// easeIn: String|Function
	//		easing function use to show pane
	easeIn: "dojo._DefaultEasing",

	// duration: Integer
	//		duration to run show/hide animations
	duration: 420,

	startExpanded: true,

	"class": "dijitExpandoPane",

	postCreate: function(){

		this.inherited(arguments);
		this._animConnects = [];

		this._isHorizontal = true;

		if(dojo.isString(this.easeOut)){
			this.easeOut = dojo.getObject(this.easeOut);
		}
		if(dojo.isString(this.easeIn)){
			this.easeIn = dojo.getObject(this.easeIn);
		}

		var thisClass = "";
		if(this.region){
			// FIXME: add suport for alternate region types?
			switch(this.region){
				case "right" :
					thisClass = "Right";
					break;
				case "left" :
					thisClass = "Left";
					break;
				case "top" :
					thisClass = "Top";
					break;
				case "bottom" :
					thisClass = "Bottom";
					break;
			}
			dojo.addClass(this.domNode, "dojoxExpando" + thisClass);
			this._isHorizontal = /top|bottom/.test(this.region);
		}
		dojo.style(this.domNode, {
			overflow: "hidden",
			padding:0
		});
	},

	startup: function(){
		this.inherited(arguments);

		this._container = this.getParent();
		this._closedSize = this._titleHeight = dojo.marginBox/*_getBorderBox*/(this.titleWrapper).h;

		if(this.splitter){
			// find our splitter and tie into it's drag logic
			var myid = this.id;
			dijit.registry.filter(function(w){
				return w && w.child && w.child.id == myid;
			}).forEach(dojo.hitch(this,function(w){
				this.connect(w,"_stopDrag","_afterResize");
			}));
		}

		this._currentSize = dojo.marginBox(this.domNode);
		this._showSize = this._currentSize[(this._isHorizontal ? "h" : "w")];
		this._setupAnims();

		if(this.startExpanded){
			this._showing = true;
		}else{
			this._hideWrapper();
			this._hideAnim.gotoPercent(99,true);
		}
	},

	_afterResize: function(e){
		var tmp = this._currentSize;
		this._currentSize = dojo.marginBox(this.domNode);
		var n = this._currentSize[(this._isHorizontal ? "h" : "w")]
		if(n > this._titleHeight){
			if(!this._showing){
				this._showing = !this._showing;
				this._showEnd();
			}
			this._showSize = n;
			this._setupAnims();
		}else{
			this._showSize = tmp[(this._isHorizontal ? "h" : "w")];
			this._showing = false;
			this._hideWrapper();
			this._hideAnim.gotoPercent(89,true);
		}

	},

	_setupAnims: function(){
		// summary: Create the show and hide animations
		dojo.forEach(this._animConnects, this.disconnect);

		var _common = {
			node:this.domNode,
			duration:this.duration
		};

		var isHorizontal = this._isHorizontal;
		var showProps = {};
		var hideProps = {};

		var dimension = isHorizontal ? "height" : "width";
		showProps[dimension] = {
			end: this._showSize,
			unit:"px"
		};
		hideProps[dimension] = {
			end: this._closedSize,
			unit:"px"
		};

		this._showAnim = dojo.animateProperty(dojo.mixin(_common,{
			easing:this.easeIn,
			properties: showProps
		}));
		this._hideAnim = dojo.animateProperty(dojo.mixin(_common,{
			easing:this.easeOut,
			properties: hideProps
		}));

		this._animConnects = [
			this.connect(this._showAnim,"onEnd","_showEnd"),
			this.connect(this._hideAnim,"onEnd","_hideEnd")
		];
	},

	toggle: function(){
		// summary: Toggle this pane's visibility
		if(this._showing){
			this._hideWrapper();
			this._showAnim && this._showAnim.stop();
			this._hideAnim.play();
		}else{
			this._hideAnim && this._hideAnim.stop();
			this._showAnim.play();
		}
		this._showing = !this._showing;
	},

	_hideWrapper: function(){
		// summary: Set the Expando state to "closed"
		dojo.addClass(this.domNode, "dojoxExpandoClosed");
		dojo.style(this.cwrapper,{
			visibility: "hidden",
			opacity: "0",
			overflow: "hidden"
		});
	},

	_showEnd: function(){
		// summary: Common animation onEnd code - "unclose"
		dojo.style(this.cwrapper, { opacity: 0, visibility:"visible" });
		dojo.fadeIn({ node:this.cwrapper, duration:227 }).play(1);
		dojo.removeClass(this.domNode, "dojoxExpandoClosed");
		setTimeout(dojo.hitch(this._container, "layout"), 15);
	},

	_hideEnd: function(){
		setTimeout(dojo.hitch(this._container, "layout"), 15);
	},

	resize: function(){
		// summary: we aren't a layout widget, but need to act like one:
		var size = dojo.marginBox(this.domNode),
			h = size.h - this._titleHeight;

		dojo.style(this.containerNode, "height", h + "px");
		this.inherited(arguments);
	},

	_trap: function(e){
		dojo.stopEvent(e);
	}

});
<|endoftext|>


<commit_before>var maps = (function() {
    var fn = {};

    fn.init_map = function (config, mapContainer) {
        if (!fn.hasOwnProperty('map')) {
            mapContainer.show();
            mapContainer.empty();
            fn.map = L.map(mapContainer[0], {trackResize: false}).setView([0, 0], 3);
            var mapId = 'mapbox.streets';
            L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
                maxZoom: 18,
                id: mapId,
                accessToken: config.mapboxAccessToken
            }).addTo(fn.map);
            L.control.scale().addTo(fn.map);

            fn.layerControl = L.control.layers();
            fn.layerControl.addTo(fn.map);

            new ZoomToFitControl().addTo(fn.map);
            $('#zoomtofit').css('display', 'block');
        } else {
            if (fn.map.activeOverlay) {
                fn.map.removeLayer(fn.map.activeOverlay);
                fn.layerControl.removeLayer(fn.map.activeOverlay);
                fn.map.activeOverlay = null;
            }
        }
    };

    fn.initPopupTempate = function (config) {
        if (!fn.template) {
            var rows = _.map(config.columns, function (col) {
                var tr = _.template("
<%= label %>	")(col);
                tr += "<%= " + col.column_id + "%>
";
                return tr;
            });
            var table = '
<%= rows %>
';
            var template = _.template(table)({rows: rows.join('')});
            fn.template = _.template(template);
        }
    };

    fn.render = function (config, data, mapContainer) {
        fn.init_map(config, mapContainer);
        fn.initPopupTempate(config);

        var bad_re = /[a-zA-Z()]+/;
        var points = _.compact(_.map(data, function (row) {
            var val = row[config.location_column_id];
            if (val !== null && !bad_re.test(val)) {
                var latlon = val.split(" ").slice(0, 2);
                return L.marker(latlon).bindPopup(fn.template(row));
            }
        }));
        if (points.length > 0) {
            var overlay = L.featureGroup(points);
            fn.layerControl.addOverlay(overlay, config.layer_name);
            overlay.addTo(fn.map);
            fn.map.activeOverlay = overlay;
            zoomToAll(fn.map);
        }
    };

    return fn;
})();
<commit_msg>add satellite layer<commit_after>var maps = (function() {
    var fn = {};

    var getTileLayer = function (layerId, accessToken) {
        return L.tileLayer('https://api.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
            id: layerId,
            accessToken: accessToken,
            maxZoom: 17
        });
    };

    fn.init_map = function (config, mapContainer) {
        if (!fn.hasOwnProperty('map')) {
            mapContainer.show();
            mapContainer.empty();
            var streets = getTileLayer('mapbox.streets', config.mapboxAccessToken),
                satellite = getTileLayer('mapbox.satellite', config.mapboxAccessToken);

            fn.map = L.map(mapContainer[0], {
                trackResize: false,
                layers: [streets]
            }).setView([0, 0], 3);

            L.control.scale().addTo(fn.map);

            var baseMaps = {};
            baseMaps[gettext("Streets")] = streets;
            baseMaps[gettext("Satellite")] = satellite;

            fn.layerControl = L.control.layers(baseMaps);
            fn.layerControl.addTo(fn.map);

            new ZoomToFitControl().addTo(fn.map);
            $('#zoomtofit').css('display', 'block');
        } else {
            if (fn.map.activeOverlay) {
                fn.map.removeLayer(fn.map.activeOverlay);
                fn.layerControl.removeLayer(fn.map.activeOverlay);
                fn.map.activeOverlay = null;
            }
        }
    };

    fn.initPopupTempate = function (config) {
        if (!fn.template) {
            var rows = _.map(config.columns, function (col) {
                var tr = _.template("
<%= label %>	")(col);
                tr += "<%= " + col.column_id + "%>
";
                return tr;
            });
            var table = '
<%= rows %>
';
            var template = _.template(table)({rows: rows.join('')});
            fn.template = _.template(template);
        }
    };

    fn.render = function (config, data, mapContainer) {
        fn.init_map(config, mapContainer);
        fn.initPopupTempate(config);

        var bad_re = /[a-zA-Z()]+/;
        var points = _.compact(_.map(data, function (row) {
            var val = row[config.location_column_id];
            if (val !== null && !bad_re.test(val)) {
                var latlon = val.split(" ").slice(0, 2);
                return L.marker(latlon).bindPopup(fn.template(row));
            }
        }));
        if (points.length > 0) {
            var overlay = L.featureGroup(points);
            fn.layerControl.addOverlay(overlay, config.layer_name);
            overlay.addTo(fn.map);
            fn.map.activeOverlay = overlay;
            zoomToAll(fn.map);
        }
    };

    return fn;
})();
<|endoftext|>


<commit_before>import React from 'react';
import {
	View,
	Text,
	ListView,
	StyleSheet,
} from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';
import moment from 'moment';
import { connect } from 'react-redux';
import { Actions } from 'react-native-router-flux';
import Touchable from '../common/Touchable';
import { platformIOS, getHumanizedDuration } from '../../util/general';
import {
	MAX_CARD_WIDTH,
	WINDOW_WIDTH,
	WINDOW_HEIGHT,
	NAVIGATOR_IOS_HEIGHT,
	NAVIGATOR_ANDROID_HEIGHT,
	TAB_BAR_HEIGHT,
} from '../../styles/LayoutConstants';
import { COLOR_BLACK } from '../../styles/ColorConstants';

const dataSource = new ListView.DataSource({
	rowHasChanged: (r1, r2) => r1 !== r2,
	sectionHeaderHasChanged: (s1, s2) => s1 !== s2
});

const ConferenceListView = ({ style, scrollEnabled, rows, personal, disabled, conferenceData, saved, addConference, removeConference }) => {
	if (personal && saved && saved.length === 0) {
		return (
			<View style={[style, rows ? styles.card : styles.full]}>
				<Text style={styles.noSavedSessions}>
					Click the star icon next to a session to save it to your list.
				</Text>
			</View>
		);
	} else {
		return (
			<ListView
				style={[style, rows ? styles.card : styles.full]}
				scrollEnabled={scrollEnabled}
				stickySectionHeadersEnabled={false}
				dataSource={dataSource.cloneWithRowsAndSections(convertArrayToMap(adjustData(conferenceData.schedule, saved, personal, rows)))}
				renderRow={(rowData, sectionID, rowID, highlightRow) => {
					// Don't render first row bc rendered by header
					if (Number(rowID) !== 0) {
						return (
							<View style={styles.rowContainer}>
								<EmptyItem />
								<ConferenceItem
									conferenceData={rowData}
									saved={isSaved(saved, rowData.id)}
									add={addConference}
									remove={removeConference}
									disabled={disabled}
								/>
							</View>
						);
					} else {
						return null;
					}
				}}
				renderSectionHeader={(sectionData, sectionID) => (
					// Render header along with first row
					<View style={styles.rowContainer}>
						<ConferenceHeader
							timestamp={sectionID}
						/>
						<ConferenceItem
							conferenceData={sectionData[0]}
							saved={isSaved(saved, sectionData[0].id)}
							add={addConference}
							remove={removeConference}
							disabled={disabled}
						/>
					</View>
				)}
			/>
		);
	}
};

function adjustData(scheduleArray, savedArray, personal, rows) {
	// Filter out saved items
	if (!personal || !savedArray) {
		if (!rows) {
			return scheduleArray;
		} else {
			const trimmed = {};
			const keys = Object.keys(scheduleArray);

			for (let i = 0; i < rows; ++i) {
				trimmed[keys[i]] = scheduleArray[keys[i]];
			}
			return trimmed;
		}
	} else {
		const filtered = {};

		if (rows) {
			for (let i = 0; i < savedArray.length && i < rows; ++i) {
				const key = savedArray[i];
				filtered[key] = scheduleArray[key];
			}
		} else {
			for (let i = 0; i < savedArray.length; ++i) {
				const key = savedArray[i];
				filtered[key] = scheduleArray[key];
			}
		}
		return filtered;
	}
}

function isSaved(savedArray, id) {
	for ( let i = 0; i < savedArray.length; ++i) {
		if (savedArray[i] === id) {
			return true;
		}
	}
	return false;
}

function convertArrayToMap(scheduleArray, header = false) {
	const scheduleMap = {};

	Object.keys(scheduleArray).forEach((key) => {
		const session = scheduleArray[key];
		if (!scheduleMap[session['start-time']]) {
			// Create an entry in the map for the timestamp if it hasn't yet been created
			scheduleMap[session['start-time']] = [];
		}
		scheduleMap[session['start-time']].push(session);
	});

	// Remove an item from section so spacing lines up
	if (header) {
		Object.keys(scheduleMap).forEach((key) => {
			scheduleMap[key].pop();
		});
	}
	return scheduleMap;
}

const ConferenceItem = ({ conferenceData, saved, add, remove, disabled }) => {
	return (
		<View
			style={styles.itemRow}
		>
			<CircleBorder />
			<View style={styles.titleContainer}>
				<Touchable
					onPress={() => Actions.ConferenceDetailView({ data: conferenceData, add, remove })}
				>
					<View>
						{conferenceData['talk-title'] ? (
							<Text
								style={styles.titleText}
								numberOfLines={2}
							>
								{conferenceData['talk-title']}
							</Text>
						) : null }

						<View style={styles.labelView}>
							{ conferenceData.label ? (
								<Text style={[styles.labelText, { color: conferenceData['label-theme'] ? conferenceData['label-theme'] : COLOR_BLACK }]}>{conferenceData.label}</Text>
							) : null }
							{ conferenceData['talk-type'] === 'Keynote' ? (
								<Text style={styles.labelText}>{conferenceData['talk-type']}</Text>
							) : null }
							{ conferenceData.label || conferenceData['talk-type'] === 'Keynote' ? (
								<Text style={styles.labelText}> - </Text>
							) : null }
							<Text style={styles.labelText}>{getHumanizedDuration(conferenceData['start-time'], conferenceData['end-time'])}</Text>
						</View>
					</View>
				</Touchable>
			</View>

			{ (!disabled) ? (
				<View style={styles.starButton}>
					<Touchable
						onPress={
							() => ((saved) ? (remove(conferenceData.id)) : (add(conferenceData.id)))
						}
					>
						<View style={styles.starButtonInner}>
							<Icon
								name={'ios-star-outline'}
								size={32}
								color={'#999'}
								style={styles.starOuterIcon}
							/>
							{ saved ? (
								<Icon
									name={'ios-star'}
									size={26}
									color={'yellow'}
									style={styles.starInnerIcon}
								/>
							) : null }
						</View>
					</Touchable>
				</View>
			) : null }
		</View>
	);
};

const EmptyItem = () => (
	<View style={styles.emptyRow} />
);

const ConferenceHeader = ({ timestamp }) => (
	<View
		style={styles.header}
	>
		<Text style={styles.headerText}>
			{moment(Number(timestamp)).format('h:mm')}
		</Text>
	</View>
);

const CircleBorder = () => (
	<View style={styles.borderContainer}>
		<View style={styles.line} />
		<View style={styles.circle} />
	</View>
);

const mapStateToProps = (state) => (
	{
		conferenceData: state.conference.data,
		saved: state.conference.saved
	}
);

const mapDispatchToProps = (dispatch) => (
	{
		addConference: (id) => {
			dispatch({ type: 'ADD_CONFERENCE', id });
		},
		removeConference: (id) => {
			dispatch({ type: 'REMOVE_CONFERENCE', id });
		}
	}
);

const ActualConferenceListView = connect(
	mapStateToProps,
	mapDispatchToProps
)(ConferenceListView);

const styles = StyleSheet.create({
	rowContainer: { flexDirection: 'row', height: 76 },
	full: { width: WINDOW_WIDTH, height: platformIOS ? (WINDOW_HEIGHT - NAVIGATOR_IOS_HEIGHT - TAB_BAR_HEIGHT) : (WINDOW_HEIGHT - NAVIGATOR_ANDROID_HEIGHT - TAB_BAR_HEIGHT) },
	card: { width: MAX_CARD_WIDTH },
	itemRow: { flexGrow: 1, flexDirection: 'row', backgroundColor: '#F9F9F9' },
	header: { justifyContent: 'flex-start', alignItems: 'center', width: 45, backgroundColor: '#F9F9F9', borderBottomWidth: 1, borderColor: '#F9F9F9' },
	headerText: { textAlign: 'right', alignSelf: 'stretch', color: '#000', fontSize: 12, marginTop: 7 },
	emptyRow: { width: 45, flexDirection: 'row',  backgroundColor: '#F9F9F9', borderBottomWidth: 1, borderColor: '#F9F9F9' },
	titleContainer: { flex: 1, marginTop: 3 },
	titleText: { alignSelf: 'stretch', fontSize: 18, color: '#000' },
	labelView: { flexDirection: 'row', paddingTop: 4 },
	labelText: { fontSize: 13 },
	starButton: { width: 50 },
	starButtonInner: { justifyContent: 'flex-start', alignItems: 'center' },
	starOuterIcon: { position: platformIOS() ? 'absolute' : 'relative', zIndex: 10, backgroundColor: 'rgba(0,0,0,0)' },
	starInnerIcon: { position: 'absolute', zIndex: platformIOS() ? 5 : 15, marginTop: 3 },
	borderContainer: { width: 1, alignSelf: 'stretch', marginHorizontal: 20, alignItems: 'flex-start' },
	line: { flexGrow: 1, borderLeftWidth: 1, borderColor: '#AAA', paddingBottom: 20 },
	circle: { position: 'absolute', top: 11, left: -2.5, height: 6, width: 6, borderRadius: 3, borderWidth: 1, borderColor: '#AAA', backgroundColor: '#F9F9F9' },
	bottomBorder: { borderBottomWidth: 1, borderBottomColor: '#DDD' },
	noSavedSessions: { flexGrow: 1, fontSize: 18, textAlign: 'center', padding: 40, lineHeight: 30 },
});

export default ActualConferenceListView;
<commit_msg>Change logic to ensure ordering of conference items<commit_after>import React from 'react';
import {
	View,
	Text,
	ListView,
	StyleSheet,
} from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';
import moment from 'moment';
import { connect } from 'react-redux';
import { Actions } from 'react-native-router-flux';
import Touchable from '../common/Touchable';
import { platformIOS, getHumanizedDuration } from '../../util/general';
import {
	MAX_CARD_WIDTH,
	WINDOW_WIDTH,
	WINDOW_HEIGHT,
	NAVIGATOR_IOS_HEIGHT,
	NAVIGATOR_ANDROID_HEIGHT,
	TAB_BAR_HEIGHT,
} from '../../styles/LayoutConstants';
import { COLOR_BLACK } from '../../styles/ColorConstants';

const dataSource = new ListView.DataSource({
	rowHasChanged: (r1, r2) => r1 !== r2,
	sectionHeaderHasChanged: (s1, s2) => s1 !== s2
});

const ConferenceListView = ({ style, scrollEnabled, rows, personal, disabled, conferenceData, saved, addConference, removeConference }) => {
	if (personal && saved && saved.length === 0) {
		return (
			<View style={[style, rows ? styles.card : styles.full]}>
				<Text style={styles.noSavedSessions}>
					Click the star icon next to a session to save it to your list.
				</Text>
			</View>
		);
	} else {
		return (
			<ListView
				style={[style, rows ? styles.card : styles.full]}
				scrollEnabled={scrollEnabled}
				stickySectionHeadersEnabled={false}
				dataSource={dataSource.cloneWithRowsAndSections(convertToTimeMap(conferenceData.schedule, adjustData(conferenceData.uids, saved, personal, rows)))}
				renderRow={(rowData, sectionID, rowID, highlightRow) => {
					// Don't render first row bc rendered by header
					if (Number(rowID) !== 0) {
						return (
							<View style={styles.rowContainer}>
								<EmptyItem />
								<ConferenceItem
									conferenceData={rowData}
									saved={isSaved(saved, rowData.id)}
									add={addConference}
									remove={removeConference}
									disabled={disabled}
								/>
							</View>
						);
					} else {
						return null;
					}
				}}
				renderSectionHeader={(sectionData, sectionID) => (
					// Render header along with first row
					<View style={styles.rowContainer}>
						<ConferenceHeader
							timestamp={sectionID}
						/>
						<ConferenceItem
							conferenceData={sectionData[0]}
							saved={isSaved(saved, sectionData[0].id)}
							add={addConference}
							remove={removeConference}
							disabled={disabled}
						/>
					</View>
				)}
			/>
		);
	}
};

function adjustData(scheduleIdArray, savedArray, personal, rows) {
	// Filter out saved items
	if (!personal || !savedArray) {
		const keys = scheduleIdArray;
		if (!rows) {
			return scheduleIdArray;
		} else {
			const trimmed = [];

			for (let i = 0; i < rows; ++i) {
				trimmed.push(keys[i]);
			}
			return trimmed;
		}
	} else {
		const filtered = [];

		if (rows) {
			for (let i = 0; i < savedArray.length && i < rows; ++i) {
				const key = savedArray[i];
				filtered.push(key);
			}
		} else {
			for (let i = 0; i < savedArray.length; ++i) {
				const key = savedArray[i];
				filtered.push(key);
			}
		}
		return filtered;
	}
}

function isSaved(savedArray, id) {
	for ( let i = 0; i < savedArray.length; ++i) {
		if (savedArray[i] === id) {
			return true;
		}
	}
	return false;
}

function convertToTimeMap(scheduleMap, scheduleArray, header = false) {
	const timeMap = {};

	scheduleArray.forEach((key) => {
		const session = scheduleMap[key];
		if (!timeMap[session['start-time']]) {
			// Create an entry in the map for the timestamp if it hasn't yet been created
			timeMap[session['start-time']] = [];
		}
		timeMap[session['start-time']].push(session);
	});

	// Remove an item from section so spacing lines up
	if (header) {
		Object.keys(timeMap).forEach((key) => {
			timeMap[key].pop();
		});
	}
	return timeMap;
}

const ConferenceItem = ({ conferenceData, saved, add, remove, disabled }) => {
	return (
		<View
			style={styles.itemRow}
		>
			<CircleBorder />
			<View style={styles.titleContainer}>
				<Touchable
					onPress={() => Actions.ConferenceDetailView({ data: conferenceData, add, remove })}
				>
					<View>
						{conferenceData['talk-title'] ? (
							<Text
								style={styles.titleText}
								numberOfLines={2}
							>
								{conferenceData['talk-title']}
							</Text>
						) : null }

						<View style={styles.labelView}>
							{ conferenceData.label ? (
								<Text style={[styles.labelText, { color: conferenceData['label-theme'] ? conferenceData['label-theme'] : COLOR_BLACK }]}>{conferenceData.label}</Text>
							) : null }
							{ conferenceData['talk-type'] === 'Keynote' ? (
								<Text style={styles.labelText}>{conferenceData['talk-type']}</Text>
							) : null }
							{ conferenceData.label || conferenceData['talk-type'] === 'Keynote' ? (
								<Text style={styles.labelText}> - </Text>
							) : null }
							<Text style={styles.labelText}>{getHumanizedDuration(conferenceData['start-time'], conferenceData['end-time'])}</Text>
						</View>
					</View>
				</Touchable>
			</View>

			{ (!disabled) ? (
				<View style={styles.starButton}>
					<Touchable
						onPress={
							() => ((saved) ? (remove(conferenceData.id)) : (add(conferenceData.id)))
						}
					>
						<View style={styles.starButtonInner}>
							<Icon
								name={'ios-star-outline'}
								size={32}
								color={'#999'}
								style={styles.starOuterIcon}
							/>
							{ saved ? (
								<Icon
									name={'ios-star'}
									size={26}
									color={'yellow'}
									style={styles.starInnerIcon}
								/>
							) : null }
						</View>
					</Touchable>
				</View>
			) : null }
		</View>
	);
};

const EmptyItem = () => (
	<View style={styles.emptyRow} />
);

const ConferenceHeader = ({ timestamp }) => (
	<View
		style={styles.header}
	>
		<Text style={styles.headerText}>
			{moment(Number(timestamp)).format('h:mm')}
		</Text>
	</View>
);

const CircleBorder = () => (
	<View style={styles.borderContainer}>
		<View style={styles.line} />
		<View style={styles.circle} />
	</View>
);

const mapStateToProps = (state) => (
	{
		conferenceData: state.conference.data,
		saved: state.conference.saved
	}
);

const mapDispatchToProps = (dispatch) => (
	{
		addConference: (id) => {
			dispatch({ type: 'ADD_CONFERENCE', id });
		},
		removeConference: (id) => {
			dispatch({ type: 'REMOVE_CONFERENCE', id });
		}
	}
);

const ActualConferenceListView = connect(
	mapStateToProps,
	mapDispatchToProps
)(ConferenceListView);

const styles = StyleSheet.create({
	rowContainer: { flexDirection: 'row', height: 76 },
	full: { width: WINDOW_WIDTH, height: platformIOS ? (WINDOW_HEIGHT - NAVIGATOR_IOS_HEIGHT - TAB_BAR_HEIGHT) : (WINDOW_HEIGHT - NAVIGATOR_ANDROID_HEIGHT - TAB_BAR_HEIGHT) },
	card: { width: MAX_CARD_WIDTH },
	itemRow: { flexGrow: 1, flexDirection: 'row', backgroundColor: '#F9F9F9' },
	header: { justifyContent: 'flex-start', alignItems: 'center', width: 45, backgroundColor: '#F9F9F9', borderBottomWidth: 1, borderColor: '#F9F9F9' },
	headerText: { textAlign: 'right', alignSelf: 'stretch', color: '#000', fontSize: 12, marginTop: 7 },
	emptyRow: { width: 45, flexDirection: 'row',  backgroundColor: '#F9F9F9', borderBottomWidth: 1, borderColor: '#F9F9F9' },
	titleContainer: { flex: 1, marginTop: 3 },
	titleText: { alignSelf: 'stretch', fontSize: 18, color: '#000' },
	labelView: { flexDirection: 'row', paddingTop: 4 },
	labelText: { fontSize: 13 },
	starButton: { width: 50 },
	starButtonInner: { justifyContent: 'flex-start', alignItems: 'center' },
	starOuterIcon: { position: platformIOS() ? 'absolute' : 'relative', zIndex: 10, backgroundColor: 'rgba(0,0,0,0)' },
	starInnerIcon: { position: 'absolute', zIndex: platformIOS() ? 5 : 15, marginTop: 3 },
	borderContainer: { width: 1, alignSelf: 'stretch', marginHorizontal: 20, alignItems: 'flex-start' },
	line: { flexGrow: 1, borderLeftWidth: 1, borderColor: '#AAA', paddingBottom: 20 },
	circle: { position: 'absolute', top: 11, left: -2.5, height: 6, width: 6, borderRadius: 3, borderWidth: 1, borderColor: '#AAA', backgroundColor: '#F9F9F9' },
	bottomBorder: { borderBottomWidth: 1, borderBottomColor: '#DDD' },
	noSavedSessions: { flexGrow: 1, fontSize: 18, textAlign: 'center', padding: 40, lineHeight: 30 },
});

export default ActualConferenceListView;
<|endoftext|>