<commit_before>// Magic Django Solution for CSRF Token Validation
var csrftoken = Cookies.get('csrftoken');
function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

function formatBytes(bytes,decimals) {
   if(bytes == 0) return '0 Byte';
   var k = 1000; // or 1024 for binary
   var dm = decimals + 1 || 3;
   var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
   var i = Math.floor(Math.log(bytes) / Math.log(k));
   return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}

function formatInUse(inUse) {
  if (inUse == 'Yes') return 'Used';
  else if (inUse == 'No') return 'Available';
  return 'Unknown';
}

function drawGraphs () {
    (function(d3) {
      d3.select('body').selectAll('svg').remove();
      // 'use strict';
      var width = 200,
        height = 200,
        radius = Math.min(width, height) / 2,
        donutWidth = 50,
        legendRectSize = 18,
        legendSpacing = 4,
        color = d3.scale.category20();

      // Common graphing variables
      var arc = d3.svg.arc()
        .innerRadius(radius - donutWidth)
        .outerRadius(radius);

      var pie = d3.layout.pie()
        .value(function(d) { return d.count; })
        .sort(null);

      // Manufacturer's Graph
      var manufacturersSvg = d3.select('#manufacturer-graph')
        .append('svg')
        .attr('width', width)
        .attr('height', height)
        .append('g')
        .attr("transform", "translate(" + Math.min(width,height) / 2 + "," + Math.min(width,height) / 2 + ")");

      // Capacity Graph
      var capacitySvg = d3.select('#capacity-graph')
        .append('svg')
        .attr('width', width)
        .attr('height', height)
        .append('g')
        .attr("transform", "translate(" + Math.min(width,height) / 2 + "," + Math.min(width,height) / 2 + ")");

      // Status Graph
      var statusSvg = d3.select('#status-graph')
        .append('svg')
        .attr('width', width)
        .attr('height', height)
        .append('g')
        .attr("transform", "translate(" + Math.min(width,height) / 2 + "," + Math.min(width,height) / 2 + ")");

      // Interface Graph
      var interfaceSvg = d3.select('#interface-graph')
        .append('svg')
        .attr('width', width)
        .attr('height', height)
        .append('g')
        .attr("transform", "translate(" + Math.min(width,height) / 2 + "," + Math.min(width,height) / 2 + ")");

      d3.json(driveAPIUrl + '?representation=original', function(error, dataset) {
        var manufacturers = {};
        var capacities = {};
        var statuses = {};
        var interfaces = {};

        dataset.forEach(function(drive) {
          var manufacturer = drive.manufacturer;
          var inUse = formatInUse(drive.in_use);
          var status = drive.status;
          var interface = drive.interface;

          manufacturers[manufacturer] = manufacturers[manufacturer] ? manufacturers[manufacturer] + 1 : 1;
          capacities[inUse] = capacities[inUse] ? capacities[inUse] + drive.capacity : drive.capacity;
          statuses[status] = statuses[status] ? statuses[status] + 1 : 1;
          interfaces[interface] = interfaces[interface] ? interfaces[interface] + 1 : 1;
        });

        manufacturers = $.map(manufacturers, function(value, index) {
          return [{"label": index, "count": value}];
        });
        capacities = $.map(capacities, function(value, index) {
          return [{"label": index, "count": value}]
        })
        statuses = $.map(statuses, function(value, index) {
          return [{"label": index, "count": value}]
        })
        interfaces = $.map(interfaces, function(value, index) {
          return [{"label": index, "count": value}]
        })

        // Draw the graph for the Manufacturer's Graph
        var manufacturersPath = manufacturersSvg.selectAll('path')
          .data(pie(manufacturers))
          .enter()
          .append('path')
          .attr('d', arc)
          .attr('fill', function(d, i) {
            return color(d.data.label);
          });

        // Add tooltips to the Manufacturer's Graph
        manufacturersPath.each(function(d,i) {
          var total = d3.sum(manufacturers.map(function(d) {
            return d.count;
          }));
          var percent = Math.round(1000 * d.data.count / total) / 10;
          var popover = $(manufacturersPath[0][i]).popover({
            'container': 'body',
            'title': d.data.label,
            'content': percent + '% of ' + total + ' drives',
            'trigger': 'hover focus'
          });
        })

        // Draw the graph for the Capacity Graph
        var capacityPath = capacitySvg.selectAll('path')
          .data(pie(capacities))
          .enter()
          .append('path')
          .attr('d', arc)
          .attr('fill', function(d, i) {
            return color(d.data.label);
          });

        // Add tooltips to the Capacity Graph
        capacityPath.each(function(d,i) {
          var total = d3.sum(capacities.map(function(d) {
            return d.count;
          }));
          var percent = Math.round(1000 * d.data.count / total) / 10;
          var popover = $(capacityPath[0][i]).popover({
            'container': 'body',
            'title': d.data.label,
            'content': percent + '% of ' + formatBytes(total),
            'trigger': 'hover focus'
          });
        })

        // Draw the graph for the Status Graph
        var statusPath = statusSvg.selectAll('path')
          .data(pie(statuses))
          .enter()
          .append('path')
          .attr('d', arc)
          .attr('fill', function(d, i) {
            return color(d.data.label);
          });

        // Add tooltips to the Capacity Graph
        statusPath.each(function(d,i) {
          var total = d3.sum(statuses.map(function(d) {
            return d.count;
          }));
          var percent = Math.round(1000 * d.data.count / total) / 10;
          var popover = $(statusPath[0][i]).popover({
            'container': 'body',
            'title': d.data.label,
            'content': percent + '% of ' + total + ' drives',
            'trigger': 'hover focus'
          });
        })

        // Draw the graph for the Interface Graph
        var interfacePath = interfaceSvg.selectAll('path')
          .data(pie(interfaces))
          .enter()
          .append('path')
          .attr('d', arc)
          .attr('fill', function(d, i) {
            return color(d.data.label);
          });

        // Add tooltips to the Capacity Graph
        interfacePath.each(function(d,i) {
          var total = d3.sum(interfaces.map(function(d) {
            return d.count;
          }));
          var percent = Math.round(1000 * d.data.count / total) / 10;
          var popover = $(interfacePath[0][i]).popover({
            'container': 'body',
            'title': d.data.label,
            'content': percent + '% of ' + total + ' drives',
            'trigger': 'hover focus'
          });
        })

      });
    })(window.d3);
  }

var lastDriveId = null;

$(document).ready(function() {
  $('#drive-table').DataTable( {
    "ajax": {
      url: driveAPIUrl,
      dataSrc: ''
    },
    "columns": [
      {"data": "id"},
      {"data": "host"},
      {"data": "serial"},
      {"data": "media_type"},
      {"data": "in_use"},
      {"data": "status"},
      {"data": "manufacturer"},
      {"data": "model"},
      {"data": "capacity"},
      {"data": "interface"},
      {"data": "rpm"}
    ]
  });

  $('#drive-table tbody').on('click', 'tr', function() {
    var table = $('#drive-table').DataTable();
    lastDriveId = table.row(this).data().id;
    var form = $('#hard-drive-form');
    $.ajax({
      url: driveFormUrl + '/' + lastDriveId + '/',
      type: "GET",
      success: function(data) {
        $(form).replaceWith(data['form_html']);
        $('#add-new-drive-modal-label').text('Edit Drive ' + lastDriveId);
        $('#add-new-drive-modal').modal('show');
      }
    });
  });

  $('#save-hard-drive-button').on('click', function() {
    var form = $('#hard-drive-form');
    var submissionUrl = driveFormUrl;
    if (lastDriveId != null) {
       submissionUrl = driveFormUrl + '/' + lastDriveId + '/';
       lastDriveId = null;
    }
    $.ajax({
      url: submissionUrl,
      type: "POST",
      data: $(form).serialize(),
      success: function(data) {
        if (!(data['success'])) {
          $(form).replaceWith(data['form_html']);
        }
        else {
          $('#add-new-drive-modal').modal('hide');
        }
      },
      error: function () {
        $(form).find('.error-message').show();
      }
    });
  });

  $('#add-new-drive-modal').on('hidden.bs.modal', function() {
    $('#drive-table').DataTable().ajax.reload();
    drawGraphs();
    $('#add-new-drive-modal-label').text('Add New Drive');
    var form = $('#hard-drive-form');
    $.ajax({
      url: driveFormUrl,
      type: "GET",
      success: function(data) {
        $(form).replaceWith(data['form_html']);
      }
    });
  });

  $('#add-new-drive-modal').on('show.bs.modal', function() {
    $('.dateinput').datetimepicker({'format': 'MM/DD/YYYY'});
  });

  drawGraphs();

  // Allow autocomplete to work inside the Bootstrap Modal
  $.fn.modal.Constructor.prototype.enforceFocus = function() {};
});
<commit_msg>Configure datatables to not change the pagination when reloading the data. Fixes #10<commit_after>// Magic Django Solution for CSRF Token Validation
var csrftoken = Cookies.get('csrftoken');
function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

function formatBytes(bytes,decimals) {
   if(bytes == 0) return '0 Byte';
   var k = 1000; // or 1024 for binary
   var dm = decimals + 1 || 3;
   var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
   var i = Math.floor(Math.log(bytes) / Math.log(k));
   return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}

function formatInUse(inUse) {
  if (inUse == 'Yes') return 'Used';
  else if (inUse == 'No') return 'Available';
  return 'Unknown';
}

function drawGraphs () {
    (function(d3) {
      d3.select('body').selectAll('svg').remove();
      // 'use strict';
      var width = 200,
        height = 200,
        radius = Math.min(width, height) / 2,
        donutWidth = 50,
        legendRectSize = 18,
        legendSpacing = 4,
        color = d3.scale.category20();

      // Common graphing variables
      var arc = d3.svg.arc()
        .innerRadius(radius - donutWidth)
        .outerRadius(radius);

      var pie = d3.layout.pie()
        .value(function(d) { return d.count; })
        .sort(null);

      // Manufacturer's Graph
      var manufacturersSvg = d3.select('#manufacturer-graph')
        .append('svg')
        .attr('width', width)
        .attr('height', height)
        .append('g')
        .attr("transform", "translate(" + Math.min(width,height) / 2 + "," + Math.min(width,height) / 2 + ")");

      // Capacity Graph
      var capacitySvg = d3.select('#capacity-graph')
        .append('svg')
        .attr('width', width)
        .attr('height', height)
        .append('g')
        .attr("transform", "translate(" + Math.min(width,height) / 2 + "," + Math.min(width,height) / 2 + ")");

      // Status Graph
      var statusSvg = d3.select('#status-graph')
        .append('svg')
        .attr('width', width)
        .attr('height', height)
        .append('g')
        .attr("transform", "translate(" + Math.min(width,height) / 2 + "," + Math.min(width,height) / 2 + ")");

      // Interface Graph
      var interfaceSvg = d3.select('#interface-graph')
        .append('svg')
        .attr('width', width)
        .attr('height', height)
        .append('g')
        .attr("transform", "translate(" + Math.min(width,height) / 2 + "," + Math.min(width,height) / 2 + ")");

      d3.json(driveAPIUrl + '?representation=original', function(error, dataset) {
        var manufacturers = {};
        var capacities = {};
        var statuses = {};
        var interfaces = {};

        dataset.forEach(function(drive) {
          var manufacturer = drive.manufacturer;
          var inUse = formatInUse(drive.in_use);
          var status = drive.status;
          var interface = drive.interface;

          manufacturers[manufacturer] = manufacturers[manufacturer] ? manufacturers[manufacturer] + 1 : 1;
          capacities[inUse] = capacities[inUse] ? capacities[inUse] + drive.capacity : drive.capacity;
          statuses[status] = statuses[status] ? statuses[status] + 1 : 1;
          interfaces[interface] = interfaces[interface] ? interfaces[interface] + 1 : 1;
        });

        manufacturers = $.map(manufacturers, function(value, index) {
          return [{"label": index, "count": value}];
        });
        capacities = $.map(capacities, function(value, index) {
          return [{"label": index, "count": value}]
        })
        statuses = $.map(statuses, function(value, index) {
          return [{"label": index, "count": value}]
        })
        interfaces = $.map(interfaces, function(value, index) {
          return [{"label": index, "count": value}]
        })

        // Draw the graph for the Manufacturer's Graph
        var manufacturersPath = manufacturersSvg.selectAll('path')
          .data(pie(manufacturers))
          .enter()
          .append('path')
          .attr('d', arc)
          .attr('fill', function(d, i) {
            return color(d.data.label);
          });

        // Add tooltips to the Manufacturer's Graph
        manufacturersPath.each(function(d,i) {
          var total = d3.sum(manufacturers.map(function(d) {
            return d.count;
          }));
          var percent = Math.round(1000 * d.data.count / total) / 10;
          var popover = $(manufacturersPath[0][i]).popover({
            'container': 'body',
            'title': d.data.label,
            'content': percent + '% of ' + total + ' drives',
            'trigger': 'hover focus'
          });
        })

        // Draw the graph for the Capacity Graph
        var capacityPath = capacitySvg.selectAll('path')
          .data(pie(capacities))
          .enter()
          .append('path')
          .attr('d', arc)
          .attr('fill', function(d, i) {
            return color(d.data.label);
          });

        // Add tooltips to the Capacity Graph
        capacityPath.each(function(d,i) {
          var total = d3.sum(capacities.map(function(d) {
            return d.count;
          }));
          var percent = Math.round(1000 * d.data.count / total) / 10;
          var popover = $(capacityPath[0][i]).popover({
            'container': 'body',
            'title': d.data.label,
            'content': percent + '% of ' + formatBytes(total),
            'trigger': 'hover focus'
          });
        })

        // Draw the graph for the Status Graph
        var statusPath = statusSvg.selectAll('path')
          .data(pie(statuses))
          .enter()
          .append('path')
          .attr('d', arc)
          .attr('fill', function(d, i) {
            return color(d.data.label);
          });

        // Add tooltips to the Capacity Graph
        statusPath.each(function(d,i) {
          var total = d3.sum(statuses.map(function(d) {
            return d.count;
          }));
          var percent = Math.round(1000 * d.data.count / total) / 10;
          var popover = $(statusPath[0][i]).popover({
            'container': 'body',
            'title': d.data.label,
            'content': percent + '% of ' + total + ' drives',
            'trigger': 'hover focus'
          });
        })

        // Draw the graph for the Interface Graph
        var interfacePath = interfaceSvg.selectAll('path')
          .data(pie(interfaces))
          .enter()
          .append('path')
          .attr('d', arc)
          .attr('fill', function(d, i) {
            return color(d.data.label);
          });

        // Add tooltips to the Capacity Graph
        interfacePath.each(function(d,i) {
          var total = d3.sum(interfaces.map(function(d) {
            return d.count;
          }));
          var percent = Math.round(1000 * d.data.count / total) / 10;
          var popover = $(interfacePath[0][i]).popover({
            'container': 'body',
            'title': d.data.label,
            'content': percent + '% of ' + total + ' drives',
            'trigger': 'hover focus'
          });
        })

      });
    })(window.d3);
  }

var lastDriveId = null;

$(document).ready(function() {
  $('#drive-table').DataTable( {
    "ajax": {
      url: driveAPIUrl,
      dataSrc: ''
    },
    "columns": [
      {"data": "id"},
      {"data": "host"},
      {"data": "serial"},
      {"data": "media_type"},
      {"data": "in_use"},
      {"data": "status"},
      {"data": "manufacturer"},
      {"data": "model"},
      {"data": "capacity"},
      {"data": "interface"},
      {"data": "rpm"}
    ]
  });

  $('#drive-table tbody').on('click', 'tr', function() {
    var table = $('#drive-table').DataTable();
    lastDriveId = table.row(this).data().id;
    var form = $('#hard-drive-form');
    $.ajax({
      url: driveFormUrl + '/' + lastDriveId + '/',
      type: "GET",
      success: function(data) {
        $(form).replaceWith(data['form_html']);
        $('#add-new-drive-modal-label').text('Edit Drive ' + lastDriveId);
        $('#add-new-drive-modal').modal('show');
      }
    });
  });

  $('#save-hard-drive-button').on('click', function() {
    var form = $('#hard-drive-form');
    var submissionUrl = driveFormUrl;
    if (lastDriveId != null) {
       submissionUrl = driveFormUrl + '/' + lastDriveId + '/';
       lastDriveId = null;
    }
    $.ajax({
      url: submissionUrl,
      type: "POST",
      data: $(form).serialize(),
      success: function(data) {
        if (!(data['success'])) {
          $(form).replaceWith(data['form_html']);
        }
        else {
          $('#add-new-drive-modal').modal('hide');
        }
      },
      error: function () {
        $(form).find('.error-message').show();
      }
    });
  });

  $('#add-new-drive-modal').on('hidden.bs.modal', function() {
    $('#drive-table').DataTable().ajax.reload(null, false);
    drawGraphs();
    $('#add-new-drive-modal-label').text('Add New Drive');
    var form = $('#hard-drive-form');
    $.ajax({
      url: driveFormUrl,
      type: "GET",
      success: function(data) {
        $(form).replaceWith(data['form_html']);
      }
    });
  });

  $('#add-new-drive-modal').on('show.bs.modal', function() {
    $('.dateinput').datetimepicker({'format': 'MM/DD/YYYY'});
  });

  drawGraphs();

  // Allow autocomplete to work inside the Bootstrap Modal
  $.fn.modal.Constructor.prototype.enforceFocus = function() {};
});
<|endoftext|>


<commit_before>import $ from "jquery";

import * as message_flags from "./message_flags";
import * as message_lists from "./message_lists";
import * as message_viewport from "./message_viewport";
import * as rows from "./rows";

/*
This library implements two related, similar concepts:

- condensing, i.e. cutting off messages taller than about a half
  screen so that they aren't distractingly tall (and offering a button
  to uncondense them).

- Collapsing, i.e. taking a message and reducing its height to a
  single line, with a button to see the content.

*/

const _message_content_height_cache = new Map();

function show_more_link(row) {
    row.find(".message_condenser").hide();
    row.find(".message_expander").show();
}

function show_condense_link(row) {
    row.find(".message_expander").hide();
    row.find(".message_condenser").show();
}

function condense_row(row) {
    const content = row.find(".message_content");
    content.addClass("condensed");
    show_more_link(row);
}

function uncondense_row(row) {
    const content = row.find(".message_content");
    content.removeClass("condensed");
    show_condense_link(row);
}

export function uncollapse(row) {
    // Uncollapse a message, restoring the condensed message [More] or
    // [Show less] link if necessary.
    const message = message_lists.current.get(rows.id(row));
    message.collapsed = false;
    message_flags.save_uncollapsed(message);

    const process_row = function process_row(row) {
        const content = row.find(".message_content");
        content.removeClass("collapsed");

        if (message.condensed === true) {
            // This message was condensed by the user, so re-show the
            // [More] link.
            condense_row(row);
        } else if (message.condensed === false) {
            // This message was un-condensed by the user, so re-show the
            // [Show less] link.
            uncondense_row(row);
        } else if (content.hasClass("could-be-condensed")) {
            // By default, condense a long message.
            condense_row(row);
        } else {
            // This was a short message, no more need for a [More] link.
            row.find(".message_expander").hide();
        }
    };

    // We also need to collapse this message in the home view
    const home_row = message_lists.home.get_row(rows.id(row));

    process_row(row);
    process_row(home_row);
}

export function collapse(row) {
    // Collapse a message, hiding the condensed message [More] or
    // [Show less] link if necessary.
    const message = message_lists.current.get(rows.id(row));
    message.collapsed = true;

    if (message.locally_echoed) {
        // Trying to collapse a locally echoed message is
        // very rare, and in our current implementation the
        // server response overwrites the flag, so we just
        // punt for now.
        return;
    }

    message_flags.save_collapsed(message);

    const process_row = function process_row(row) {
        row.find(".message_content").addClass("collapsed");
        show_more_link(row);
    };

    // We also need to collapse this message in the home view
    const home_row = message_lists.home.get_row(rows.id(row));

    process_row(row);
    process_row(home_row);
}

export function toggle_collapse(message) {
    if (message.is_me_message) {
        // Disabled temporarily because /me messages don't have a
        // styling for collapsing /me messages (they only recently
        // added multi-line support).  See also popovers.js.
        return;
    }

    // This function implements a multi-way toggle, to try to do what
    // the user wants for messages:
    //
    // * If the message is currently showing any [More] link, either
    //   because it was previously condensed or collapsed, fully display it.
    // * If the message is fully visible, either because it's too short to
    //   condense or because it's already uncondensed, collapse it

    const row = message_lists.current.get_row(message.id);
    if (!row) {
        return;
    }

    const content = row.find(".message_content");
    const is_condensable = content.hasClass("could-be-condensed");
    const is_condensed = content.hasClass("condensed");
    if (message.collapsed) {
        if (is_condensable) {
            message.condensed = true;
            content.addClass("condensed");
            show_message_expander(row);
            row.find(".message_condenser").hide();
        }
        uncollapse(row);
    } else {
        if (is_condensed) {
            message.condensed = false;
            content.removeClass("condensed");
            hide_message_expander(row);
            row.find(".message_condenser").show();
        } else {
            collapse(row);
        }
    }
}

export function clear_message_content_height_cache() {
    _message_content_height_cache.clear();
}

export function un_cache_message_content_height(message_id) {
    _message_content_height_cache.delete(message_id);
}

function get_message_height(elem, message_id) {
    if (_message_content_height_cache.has(message_id)) {
        return _message_content_height_cache.get(message_id);
    }

    // shown to be ~2.5x faster than Node.getBoundingClientRect().
    const height = elem.offsetHeight;
    _message_content_height_cache.set(message_id, height);
    return height;
}

export function hide_message_expander(row) {
    if (row.find(".could-be-condensed").length !== 0) {
        row.find(".message_expander").hide();
    }
}

export function hide_message_condenser(row) {
    if (row.find(".could-be-condensed").length !== 0) {
        row.find(".message_condenser").hide();
    }
}

export function show_message_expander(row) {
    if (row.find(".could-be-condensed").length !== 0) {
        row.find(".message_expander").show();
    }
}

export function show_message_condenser(row) {
    if (row.find(".could-be-condensed").length !== 0) {
        row.find(".message_condenser").show();
    }
}

export function condense_and_collapse(elems) {
    const height_cutoff = message_viewport.height() * 0.65;

    for (const elem of elems) {
        const content = $(elem).find(".message_content");

        if (content.length !== 1) {
            // We could have a "/me did this" message or something
            // else without a `message_content` div.
            continue;
        }

        const message_id = rows.id($(elem));

        if (!message_id) {
            continue;
        }

        const message = message_lists.current.get(message_id);
        if (message === undefined) {
            continue;
        }

        const message_height = get_message_height(elem, message.id);
        const long_message = message_height > height_cutoff;
        if (long_message) {
            // All long messages are flagged as such.
            content.addClass("could-be-condensed");
        } else {
            content.removeClass("could-be-condensed");
        }

        // If message.condensed is defined, then the user has manually
        // specified whether this message should be expanded or condensed.
        if (message.condensed === true) {
            condense_row($(elem));
            continue;
        }

        if (message.condensed === false) {
            uncondense_row($(elem));
            continue;
        }

        if (long_message) {
            // By default, condense a long message.
            condense_row($(elem));
        } else {
            content.removeClass("condensed");
            $(elem).find(".message_expander").hide();
        }

        // Completely hide the message and replace it with a [More]
        // link if the user has collapsed it.
        if (message.collapsed) {
            content.addClass("collapsed");
            $(elem).find(".message_expander").show();
        }
    }
}

export function initialize() {
    $("#message_feed_container").on("click", ".message_expander", function (e) {
        // Expanding a message can mean either uncollapsing or
        // uncondensing it.
        const row = $(this).closest(".message_row");
        const message = message_lists.current.get(rows.id(row));
        const content = row.find(".message_content");
        if (message.collapsed) {
            // Uncollapse.
            uncollapse(row);
        } else if (content.hasClass("condensed")) {
            // Uncondense (show the full long message).
            message.condensed = false;
            content.removeClass("condensed");
            $(this).hide();
            row.find(".message_condenser").show();
        }
        e.stopPropagation();
        e.preventDefault();
    });

    $("#message_feed_container").on("click", ".message_condenser", function (e) {
        const row = $(this).closest(".message_row");
        message_lists.current.get(rows.id(row)).condensed = true;
        condense_row(row);
        e.stopPropagation();
        e.preventDefault();
    });
}
<commit_msg>condense: Do not cache message_content height of 0 from recent_topics.<commit_after>import $ from "jquery";

import * as message_flags from "./message_flags";
import * as message_lists from "./message_lists";
import * as message_viewport from "./message_viewport";
import * as recent_topics_util from "./recent_topics_util";
import * as rows from "./rows";

/*
This library implements two related, similar concepts:

- condensing, i.e. cutting off messages taller than about a half
  screen so that they aren't distractingly tall (and offering a button
  to uncondense them).

- Collapsing, i.e. taking a message and reducing its height to a
  single line, with a button to see the content.

*/

const _message_content_height_cache = new Map();

function show_more_link(row) {
    row.find(".message_condenser").hide();
    row.find(".message_expander").show();
}

function show_condense_link(row) {
    row.find(".message_expander").hide();
    row.find(".message_condenser").show();
}

function condense_row(row) {
    const content = row.find(".message_content");
    content.addClass("condensed");
    show_more_link(row);
}

function uncondense_row(row) {
    const content = row.find(".message_content");
    content.removeClass("condensed");
    show_condense_link(row);
}

export function uncollapse(row) {
    // Uncollapse a message, restoring the condensed message [More] or
    // [Show less] link if necessary.
    const message = message_lists.current.get(rows.id(row));
    message.collapsed = false;
    message_flags.save_uncollapsed(message);

    const process_row = function process_row(row) {
        const content = row.find(".message_content");
        content.removeClass("collapsed");

        if (message.condensed === true) {
            // This message was condensed by the user, so re-show the
            // [More] link.
            condense_row(row);
        } else if (message.condensed === false) {
            // This message was un-condensed by the user, so re-show the
            // [Show less] link.
            uncondense_row(row);
        } else if (content.hasClass("could-be-condensed")) {
            // By default, condense a long message.
            condense_row(row);
        } else {
            // This was a short message, no more need for a [More] link.
            row.find(".message_expander").hide();
        }
    };

    // We also need to collapse this message in the home view
    const home_row = message_lists.home.get_row(rows.id(row));

    process_row(row);
    process_row(home_row);
}

export function collapse(row) {
    // Collapse a message, hiding the condensed message [More] or
    // [Show less] link if necessary.
    const message = message_lists.current.get(rows.id(row));
    message.collapsed = true;

    if (message.locally_echoed) {
        // Trying to collapse a locally echoed message is
        // very rare, and in our current implementation the
        // server response overwrites the flag, so we just
        // punt for now.
        return;
    }

    message_flags.save_collapsed(message);

    const process_row = function process_row(row) {
        row.find(".message_content").addClass("collapsed");
        show_more_link(row);
    };

    // We also need to collapse this message in the home view
    const home_row = message_lists.home.get_row(rows.id(row));

    process_row(row);
    process_row(home_row);
}

export function toggle_collapse(message) {
    if (message.is_me_message) {
        // Disabled temporarily because /me messages don't have a
        // styling for collapsing /me messages (they only recently
        // added multi-line support).  See also popovers.js.
        return;
    }

    // This function implements a multi-way toggle, to try to do what
    // the user wants for messages:
    //
    // * If the message is currently showing any [More] link, either
    //   because it was previously condensed or collapsed, fully display it.
    // * If the message is fully visible, either because it's too short to
    //   condense or because it's already uncondensed, collapse it

    const row = message_lists.current.get_row(message.id);
    if (!row) {
        return;
    }

    const content = row.find(".message_content");
    const is_condensable = content.hasClass("could-be-condensed");
    const is_condensed = content.hasClass("condensed");
    if (message.collapsed) {
        if (is_condensable) {
            message.condensed = true;
            content.addClass("condensed");
            show_message_expander(row);
            row.find(".message_condenser").hide();
        }
        uncollapse(row);
    } else {
        if (is_condensed) {
            message.condensed = false;
            content.removeClass("condensed");
            hide_message_expander(row);
            row.find(".message_condenser").show();
        } else {
            collapse(row);
        }
    }
}

export function clear_message_content_height_cache() {
    _message_content_height_cache.clear();
}

export function un_cache_message_content_height(message_id) {
    _message_content_height_cache.delete(message_id);
}

function get_message_height(elem, message_id) {
    if (_message_content_height_cache.has(message_id)) {
        return _message_content_height_cache.get(message_id);
    }

    // shown to be ~2.5x faster than Node.getBoundingClientRect().
    const height = elem.offsetHeight;
    if (!recent_topics_util.is_visible()) {
        _message_content_height_cache.set(message_id, height);
    }
    return height;
}

export function hide_message_expander(row) {
    if (row.find(".could-be-condensed").length !== 0) {
        row.find(".message_expander").hide();
    }
}

export function hide_message_condenser(row) {
    if (row.find(".could-be-condensed").length !== 0) {
        row.find(".message_condenser").hide();
    }
}

export function show_message_expander(row) {
    if (row.find(".could-be-condensed").length !== 0) {
        row.find(".message_expander").show();
    }
}

export function show_message_condenser(row) {
    if (row.find(".could-be-condensed").length !== 0) {
        row.find(".message_condenser").show();
    }
}

export function condense_and_collapse(elems) {
    const height_cutoff = message_viewport.height() * 0.65;

    for (const elem of elems) {
        const content = $(elem).find(".message_content");

        if (content.length !== 1) {
            // We could have a "/me did this" message or something
            // else without a `message_content` div.
            continue;
        }

        const message_id = rows.id($(elem));

        if (!message_id) {
            continue;
        }

        const message = message_lists.current.get(message_id);
        if (message === undefined) {
            continue;
        }

        const message_height = get_message_height(elem, message.id);
        const long_message = message_height > height_cutoff;
        if (long_message) {
            // All long messages are flagged as such.
            content.addClass("could-be-condensed");
        } else {
            content.removeClass("could-be-condensed");
        }

        // If message.condensed is defined, then the user has manually
        // specified whether this message should be expanded or condensed.
        if (message.condensed === true) {
            condense_row($(elem));
            continue;
        }

        if (message.condensed === false) {
            uncondense_row($(elem));
            continue;
        }

        if (long_message) {
            // By default, condense a long message.
            condense_row($(elem));
        } else {
            content.removeClass("condensed");
            $(elem).find(".message_expander").hide();
        }

        // Completely hide the message and replace it with a [More]
        // link if the user has collapsed it.
        if (message.collapsed) {
            content.addClass("collapsed");
            $(elem).find(".message_expander").show();
        }
    }
}

export function initialize() {
    $("#message_feed_container").on("click", ".message_expander", function (e) {
        // Expanding a message can mean either uncollapsing or
        // uncondensing it.
        const row = $(this).closest(".message_row");
        const message = message_lists.current.get(rows.id(row));
        const content = row.find(".message_content");
        if (message.collapsed) {
            // Uncollapse.
            uncollapse(row);
        } else if (content.hasClass("condensed")) {
            // Uncondense (show the full long message).
            message.condensed = false;
            content.removeClass("condensed");
            $(this).hide();
            row.find(".message_condenser").show();
        }
        e.stopPropagation();
        e.preventDefault();
    });

    $("#message_feed_container").on("click", ".message_condenser", function (e) {
        const row = $(this).closest(".message_row");
        message_lists.current.get(rows.id(row)).condensed = true;
        condense_row(row);
        e.stopPropagation();
        e.preventDefault();
    });
}
<|endoftext|>


<commit_before>var gutil = require('gulp-util');
var load  = require('load-resources');
var path  = require('path');

var error = function (url, message) {
    var err = new gutil.PluginError('integration', {
        showStack: false,
        message:   message
    });
    err.url = url;
    return err;
};

var sites = [
    ['GitHub',    'https://github.com/'],
    ['Twitter',   'https://twitter.com/'],
    ['Bootstrap', 'github:twbs/bootstrap:dist/css/bootstrap.css'],
    ['Habrahabr', 'http://habrahabr.ru/']
];

module.exports = function (done, extra, callback) {
    if ( !callback ) {
        callback = extra;
        extra    = undefined;
    }

    var lastDomain = false;
    var caseIndex  = -1;

    var cases = sites;
    if ( extra ) cases = cases.concat(extra);

    var urls = cases.map(function (i) {
        return i[1];
    });

    load(urls, '.css', function (css, url, last) {
        var result;
        try {
            result = callback(css);
        } catch (e) {
            return done(error(url, 'Parsing error: ' + e.message + e.stack));
        }

        if ( result.css !== css ) {
            return done(error(url, 'Output is not equal input'));
        }

        var domain = url.match(/https?:\/\/[^\/]+/)[0];
        if ( domain !== lastDomain ) {
            lastDomain = domain;
            caseIndex += 1;
            gutil.log('Test ' + cases[caseIndex][0] + ' styles');
        }
        gutil.log('     ' + gutil.colors.green(path.basename(url)));

        if ( last ) done();
    });
};
<commit_msg>Better error display<commit_after>var gutil = require('gulp-util');
var load  = require('load-resources');
var path  = require('path');

var error = function (url, message) {
    var err = new gutil.PluginError('integration', {
        showStack: false,
        message:   message
    });
    err.url = url;
    return err;
};

var sites = [
    ['GitHub',    'https://github.com/'],
    ['Twitter',   'https://twitter.com/'],
    ['Bootstrap', 'github:twbs/bootstrap:dist/css/bootstrap.css'],
    ['Habrahabr', 'http://habrahabr.ru/']
];

module.exports = function (done, extra, callback) {
    if ( !callback ) {
        callback = extra;
        extra    = undefined;
    }

    var lastDomain = false;
    var caseIndex  = -1;

    var cases = sites;
    if ( extra ) cases = cases.concat(extra);

    var urls = cases.map(function (i) {
        return i[1];
    });

    load(urls, '.css', function (css, url, last) {
        var result;
        try {
            result = callback(css).css;
        } catch (e) {
            return done(error(url, 'Parsing error: ' + e.message + e.stack));
        }

        if ( result !== css ) {
            return done(error(url, 'Output is not equal input'));
        }

        var domain = url.match(/https?:\/\/[^\/]+/)[0];
        if ( domain !== lastDomain ) {
            lastDomain = domain;
            caseIndex += 1;
            gutil.log('Test ' + cases[caseIndex][0] + ' styles');
        }
        gutil.log('     ' + gutil.colors.green(path.basename(url)));

        if ( last ) done();
    });
};
<|endoftext|>


<commit_before>//
// Copyright (c) 2016 Satoshi Nakajima (https://github.com/snakajima)
// License: The MIT License
//

import React, { Component } from 'react';
import DragContext from './DragContext';

class Selection extends Component {
  constructor(props) {
    super();
    this.onDragStart = this.onDragStart.bind(this);
    this.onDrag = this.onDrag.bind(this);
  }

  onDragStart(e,handle) {
    const element = this.props.element;
    const scale = this.props.scale;
    DragContext.setContext({
      pageIndex:this.props.pageIndex,
      id:element.id, handle:handle,
      index:this.props.index,
      params:{},
      width:scale * element.w,
      height:scale * element.h,
      x:e.clientX, y:e.clientY });
  }
  onDrag(e) {
    var context = DragContext.getContext();
    //const element = context.element;
    //console.log('onDrag', context.handle, element.x, element.w);
    if (context.handle === 'turn') {
      const dx = e.clientX - context.x;
      const dy = e.clientY - context.y - context.height/2 - 20;
      const r = Math.round(Math.atan2(dy,dx) * 180 / Math.PI + 360 + 90) % 360;
      //console.log('onDrag', dx, dy, r);
      context.params.rotate = r;
      window.store.dispatch({type:'setSelectionStyle', style:{transform:"rotate("+r+"deg)"}});
    } else if (context.handle === 'ne') {
      const dx = e.clientX - (context.x - context.width/2);
      const dy = e.clientY - (context.y + context.height/2);
      const r = Math.sqrt(dx * dx + dy * dy);
      const r0 = Math.sqrt(context.width/2 * context.width/2, context.height/2 * context.height/2);
      const ratio = r / r0;
      context.params.ratio = ratio;
      console.log('onDrag', r, r0, ratio);
      window.store.dispatch({type:'setSelectionStyle', style:{transform:"scale("+ratio+")"}});
    }
  }

  render() {
    const scale = this.props.scale;
    const element = this.props.element;
    const x = element.x * scale;
    const y = element.y * scale;
    const w = element.w * scale;
    const h = element.h * scale;
    var style = {left:x, top:y, position:'absolute', width:w, height:h};
    //console.log("Selection.style", this.props.selectionStyle);
    if (this.props.selectionStyle) {
       style=Object.assign(style, this.props.selectionStyle);
    }
    return (

this.onDragStart(e,"move")}
        />
        this.onDragStart(e,"turn")}
            onDrag={this.onDrag}
        />
        this.onDragStart(e,"n")}
            onDrag={this.onDrag}
        />
        this.onDragStart(e,"s")}
            onDrag={this.onDrag}
        />
        this.onDragStart(e,"w")}
            onDrag={this.onDrag}
        />
        this.onDragStart(e,"e")}
            onDrag={this.onDrag}
        />
        this.onDragStart(e,"nw")}
            onDrag={this.onDrag}
        />
        this.onDragStart(e,"ne")}
            onDrag={this.onDrag}
        />
        this.onDragStart(e,"sw")}
            onDrag={this.onDrag}
        />
        this.onDragStart(e,"se")}
            onDrag={this.onDrag}
        />

    );
  }
}

export default Selection;
<commit_msg>scaled selection<commit_after>//
// Copyright (c) 2016 Satoshi Nakajima (https://github.com/snakajima)
// License: The MIT License
//

import React, { Component } from 'react';
import DragContext from './DragContext';

class Selection extends Component {
  constructor(props) {
    super();
    this.onDragStart = this.onDragStart.bind(this);
    this.onDrag = this.onDrag.bind(this);
  }

  onDragStart(e,handle) {
    const element = this.props.element;
    const scale = this.props.scale;
    var context = {
      pageIndex:this.props.pageIndex,
      id:element.id, handle:handle,
      index:this.props.index,
      params:{},
      width:scale * element.w,
      height:scale * element.h,
      x:e.clientX, y:e.clientY };
    if (element.scale) {
       context.width *= element.scale[0];
       context.height *= element.scale[1];
    }
    DragContext.setContext(context);
  }
  onDrag(e) {
    var context = DragContext.getContext();
    //const element = context.element;
    //console.log('onDrag', context.handle, element.x, element.w);
    if (context.handle === 'turn') {
      const dx = e.clientX - context.x;
      const dy = e.clientY - context.y - context.height/2 - 20;
      const r = Math.round(Math.atan2(dy,dx) * 180 / Math.PI + 360 + 90) % 360;
      //console.log('onDrag', dx, dy, r);
      context.params.rotate = r;
      window.store.dispatch({type:'setSelectionStyle', style:{transform:"rotate("+r+"deg)"}});
    } else if (context.handle === 'ne') {
      const dx = e.clientX - (context.x - context.width/2);
      const dy = e.clientY - (context.y + context.height/2);
      const r = Math.sqrt(dx * dx + dy * dy);
      const r0 = Math.sqrt(context.width/2 * context.width/2, context.height/2 * context.height/2);
      const ratio = r / r0;
      context.params.ratio = ratio;
      console.log('onDrag', r, r0, ratio);
      window.store.dispatch({type:'setSelectionStyle', style:{transform:"scale("+ratio+")"}});
    }
  }

  render() {
    const scale = this.props.scale;
    const element = this.props.element;
    var x = element.x * scale;
    var y = element.y * scale;
    var w = element.w * scale;
    var h = element.h * scale;
    if (element.scale) {
       x -= element.w * (element.scale[0] - 1) / 2;
       y -= element.h * (element.scale[1] - 1) / 2;
       w *= element.scale[0];
       h *= element.scale[1];
    }
    var style = {left:x, top:y, position:'absolute', width:w, height:h};
    //console.log("Selection.style", this.props.selectionStyle);
    if (this.props.selectionStyle) {
       style=Object.assign(style, this.props.selectionStyle);
    }
    return (

this.onDragStart(e,"move")}
        />
        this.onDragStart(e,"turn")}
            onDrag={this.onDrag}
        />
        this.onDragStart(e,"n")}
            onDrag={this.onDrag}
        />
        this.onDragStart(e,"s")}
            onDrag={this.onDrag}
        />
        this.onDragStart(e,"w")}
            onDrag={this.onDrag}
        />
        this.onDragStart(e,"e")}
            onDrag={this.onDrag}
        />
        this.onDragStart(e,"nw")}
            onDrag={this.onDrag}
        />
        this.onDragStart(e,"ne")}
            onDrag={this.onDrag}
        />
        this.onDragStart(e,"sw")}
            onDrag={this.onDrag}
        />
        this.onDragStart(e,"se")}
            onDrag={this.onDrag}
        />

    );
  }
}

export default Selection;
<|endoftext|>


<commit_before>/* Dispatch area - Should be eliminate after dispatching */

var markersGroup = new L.LayerGroup();
var isDispatching = false;
var placeIcon = L.icon({
    iconUrl: '/static/icons/place_marker.png',
    iconSize: [50, 50], // size of the icon
});
var dispatchingAmbulances = {};

var beginDispatching = function () {

    isDispatching = true;
    console.log('Begin dispatching.');

    document.getElementById('dispatch_work').innerHTML
        = '<button type="button" class="btn btn-link" onclick="endDispatching()">'
        + ''
        + 'Go back'
        + '</button>';
    $('#dispatchForm').collapse('show');
    $('#collapse1').collapse('hide');
    $('#collapse2').collapse('hide');

    mymap.on('click', function (e) {

        markersGroup.clearLayers();
        document.getElementById('curr-lat').innerHTML = e.latlng.lat;
        document.getElementById('curr-lng').innerHTML = e.latlng.lng;
        if (isDispatching) {
            L.marker([e.latlng.lat, e.latlng.lng], {icon: placeIcon}).addTo(markersGroup);
            markersGroup.addTo(mymap);
        }

    });

}

var endDispatching = function () {

    isDispatching = false;
    dispatchingAmbulances = {};
    console.log('End dispatching.');

    markersGroup.clearLayers();
    document.getElementById('dispatch_work').innerHTML
        = '<button class="btn btn-primary" style="display: block; width: 100%;"'
        + 'data-toggle="collapse" href="#dispatchForm" onclick="beginDispatching()">'
        + 'Dispatch'
        + '</button>';
    $('#dispatchForm').collapse('hide');
    $('#collapse1').collapse('show');
    $('#collapse2').collapse('show');

}

var handleDispatchDrop = function(e) {

    // button was dropped
    console.log('Dropped!');

}

var addToDispatchingList = function(ambulance) {

    if (isDispatching && !(ambulance.id in dispatchingAmbulances)) {

        // Available
        if (ambulance.status != STATUS_AVAILABLE) {
            alert('Can only dispatch available ambulances!');
            return;
        }

        // add ambulance to list of dispatching ambulances
        dispatchingAmbulances[ambulance.id] = true;

        // add button to grid
        $('#ambulance-selection').append(
            '<button id="dispatch-button-' + ambulance.id + '" ' +
            'type="button" class="btn btn-sm btn-success" draggable="true">'
            + ambulance.identifier
            + '</button>'
        );
        $('#dispatch-button-' + ambulance.id)
            .on('dragstart', function(e) {
                console.log('dragstart');
                this.style.opacity = '0.4';
                e.originalEvent.dataTransfer.setData("ambulance_id", ambulance.id);
            })
            .on('dragend', function(e) {
                console.log('dragend');
                // Remove if not dropped
                if(e.originalEvent.dataTransfer.dropEffect !== 'none'){
                    $(this).remove();
                } else {
                    this.style.opacity = '1.0';
                }
            });
    }
}

$("#street").change(function (data) {

    var addressInput = document.getElementById('street').value;
    console.log('Received address: ' + addressInput);

    var geocoder = new google.maps.Geocoder();

    geocoder.geocode({address: addressInput}, function (results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
            var coordinate = results[0].geometry.location;

            document.getElementById('curr-lat').innerHTML = coordinate.lat();
            document.getElementById('curr-lng').innerHTML = coordinate.lng();

            L.marker([coordinate.lat(), coordinate.lng()], {icon: placeIcon}).addTo(markersGroup);
            markersGroup.addTo(mymap);
            mymap.setView(new L.LatLng(coordinate.lat(), coordinate.lng()), 17);
        }
        else {
            alert("There is error from Google map server");
        }
    });

});

/*
 * postDispatchCall makes an ajax post request to post dispatched ambulance.
 * @param void.
 * @return void.
 */
function postDispatchCall() {
    var formData = {};
    var assigned_ambulances = [];

    // Extract form value to JSON
    formData["stmain_number"] = $('#street').val();
    formData["residential_unit"] = $('#address').val();
    formData["latitude"] = document.getElementById('curr-lat').innerHTML;
    formData["longitude"] = document.getElementById('curr-lng').innerHTML;
    formData["active"] = true
    formData["name"] = "Make Dynamic for Future"
    console.log(formData["active"])

    console.log(formData["latitude"]);
    formData["description"] = $('#comment').val();
    formData["priority"] = $('input:radio[name=priority]:checked').val();
    $('input:checkbox[name="ambulance_assignment"]:checked').each(function (i) {
        assigned_ambulances[i] = $(this).val();
    });

    if (formData["priority"] == undefined) {
        alert("Please click one of priorities");
        return;
    }

    if (assigned_ambulances.length == 0) {
        alert("Please dispatch at least one ambulance");
        return;
    }

    formData["ambulance"] = assigned_ambulances.toString();

    let postJsonUrl = 'api/calls/';
    alert(JSON.stringify(formData) + '\n' + postJsonUrl);

    var csrftoken = getCookie('csrftoken');

    $.ajaxSetup({
        beforeSend: function (xhr, settings) {
            if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                xhr.setRequestHeader("X-CSRFToken", csrftoken);
            }
        }
    })

    $.ajax({
        url: postJsonUrl,
        type: 'POST',
        dataType: 'json',
        data: formData,
        success: function (data) {
            // alert(JSON.stringify(data));
            var successMsg = 'Success
' +
                +'Ambulance: ' + data['ambulance']
                + ' dispatched to
' + data['residential_unit']
                + ', ' + data['stmain_number'] + ', ' + data['latitude'] + ', ' + data['longitude'];
            $('.modal-body').html(successMsg).addClass('alert-success');
            $('.modal-title').append('Successfully Dispached');
            $("#dispatchModal").modal('show');
            endDispatching();
        },
        error: function (jqXHR, textStatus, errorThrown) {
            alert(JSON.stringify(jqXHR) + ' ' + textStatus);
            $('.modal-title').append('Dispatch failed');
            $("#dispatchModal").modal('show');
            endDispatching();
        }
    });
}

function csrfSafeMethod(method) {
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

/*
 * getCookie extracts the csrf token for form submit
 */
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = $.trim(cookies[i]);
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

/* Functions to fill autocomplete AND to click specific locations */
function initAutocomplete() {
    // Create the autocomplete object, restricting the search to geographical
    autocomplete = new google.maps.places.Autocomplete((document.getElementById('street')),
        {types: ['geocode']});
    //autocomplete.addListener('place_changed', fillInAddress);
}<commit_msg>Separating dispatch from map.js<commit_after>/* Dispatch area - Should be eliminate after dispatching */

var markersGroup = new L.LayerGroup();
var isDispatching = false;
var placeIcon = L.icon({
    iconUrl: '/static/icons/place_marker.png',
    iconSize: [50, 50], // size of the icon
});
var dispatchingAmbulances = {};

var beginDispatching = function () {

    isDispatching = true;
    console.log('Begin dispatching.');

    document.getElementById('dispatch_work').innerHTML
        = '<button type="button" class="btn btn-link" onclick="endDispatching()">'
        + ''
        + 'Go back'
        + '</button>';
    $('#dispatchForm').collapse('show');
    $('#collapse1').collapse('hide');
    $('#collapse2').collapse('hide');

    mymap.on('click', function (e) {

        markersGroup.clearLayers();
        document.getElementById('curr-lat').innerHTML = e.latlng.lat;
        document.getElementById('curr-lng').innerHTML = e.latlng.lng;
        if (isDispatching) {
            L.marker([e.latlng.lat, e.latlng.lng], {icon: placeIcon}).addTo(markersGroup);
            markersGroup.addTo(mymap);
        }

    });

}

var endDispatching = function () {

    isDispatching = false;
    dispatchingAmbulances = {};
    console.log('End dispatching.');

    markersGroup.clearLayers();
    document.getElementById('dispatch_work').innerHTML
        = '<button class="btn btn-primary" style="display: block; width: 100%;"'
        + 'data-toggle="collapse" href="#dispatchForm" onclick="beginDispatching()">'
        + 'Dispatch'
        + '</button>';
    $('#dispatchForm').collapse('hide');
    $('#collapse1').collapse('show');
    $('#collapse2').collapse('show');

}

var handleDispatchDrop = function(e) {

    // button was dropped
    console.log('Dropped!');

}

var addToDispatchingList = function(ambulance) {

    if (isDispatching && !(ambulance.id in dispatchingAmbulances)) {

        // Available
        if (ambulance.status != STATUS_AVAILABLE) {
            alert('Can only dispatch available ambulances!');
            return;
        }

        // add ambulance to list of dispatching ambulances
        dispatchingAmbulances[ambulance.id] = true;

        // add button to grid
        $('#ambulance-selection').append(
            '<button id="dispatch-button-' + ambulance.id + '" ' +
            'type="button" class="btn btn-sm btn-success" draggable="true">'
            + ambulance.identifier
            + '</button>'
        );
        $('#dispatch-button-' + ambulance.id)
            .on('dragstart', function(e) {
                console.log('dragstart');
                this.style.opacity = '0.4';
                e.originalEvent.dataTransfer.setData("ambulance_id", ambulance.id);
            })
            .on('dragend', function(e) {
                console.log('dragend');
                // Remove if not dropped
                if(e.originalEvent.dataTransfer.dropEffect == 'none'){
                    $(this).remove();
                } else {
                    this.style.opacity = '1.0';
                }
            });
    }
}

$("#street").change(function (data) {

    var addressInput = document.getElementById('street').value;
    console.log('Received address: ' + addressInput);

    var geocoder = new google.maps.Geocoder();

    geocoder.geocode({address: addressInput}, function (results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
            var coordinate = results[0].geometry.location;

            document.getElementById('curr-lat').innerHTML = coordinate.lat();
            document.getElementById('curr-lng').innerHTML = coordinate.lng();

            L.marker([coordinate.lat(), coordinate.lng()], {icon: placeIcon}).addTo(markersGroup);
            markersGroup.addTo(mymap);
            mymap.setView(new L.LatLng(coordinate.lat(), coordinate.lng()), 17);
        }
        else {
            alert("There is error from Google map server");
        }
    });

});

/*
 * postDispatchCall makes an ajax post request to post dispatched ambulance.
 * @param void.
 * @return void.
 */
function postDispatchCall() {
    var formData = {};
    var assigned_ambulances = [];

    // Extract form value to JSON
    formData["stmain_number"] = $('#street').val();
    formData["residential_unit"] = $('#address').val();
    formData["latitude"] = document.getElementById('curr-lat').innerHTML;
    formData["longitude"] = document.getElementById('curr-lng').innerHTML;
    formData["active"] = true
    formData["name"] = "Make Dynamic for Future"
    console.log(formData["active"])

    console.log(formData["latitude"]);
    formData["description"] = $('#comment').val();
    formData["priority"] = $('input:radio[name=priority]:checked').val();
    $('input:checkbox[name="ambulance_assignment"]:checked').each(function (i) {
        assigned_ambulances[i] = $(this).val();
    });

    if (formData["priority"] == undefined) {
        alert("Please click one of priorities");
        return;
    }

    if (assigned_ambulances.length == 0) {
        alert("Please dispatch at least one ambulance");
        return;
    }

    formData["ambulance"] = assigned_ambulances.toString();

    let postJsonUrl = 'api/calls/';
    alert(JSON.stringify(formData) + '\n' + postJsonUrl);

    var csrftoken = getCookie('csrftoken');

    $.ajaxSetup({
        beforeSend: function (xhr, settings) {
            if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                xhr.setRequestHeader("X-CSRFToken", csrftoken);
            }
        }
    })

    $.ajax({
        url: postJsonUrl,
        type: 'POST',
        dataType: 'json',
        data: formData,
        success: function (data) {
            // alert(JSON.stringify(data));
            var successMsg = 'Success
' +
                +'Ambulance: ' + data['ambulance']
                + ' dispatched to
' + data['residential_unit']
                + ', ' + data['stmain_number'] + ', ' + data['latitude'] + ', ' + data['longitude'];
            $('.modal-body').html(successMsg).addClass('alert-success');
            $('.modal-title').append('Successfully Dispached');
            $("#dispatchModal").modal('show');
            endDispatching();
        },
        error: function (jqXHR, textStatus, errorThrown) {
            alert(JSON.stringify(jqXHR) + ' ' + textStatus);
            $('.modal-title').append('Dispatch failed');
            $("#dispatchModal").modal('show');
            endDispatching();
        }
    });
}

function csrfSafeMethod(method) {
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

/*
 * getCookie extracts the csrf token for form submit
 */
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = $.trim(cookies[i]);
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

/* Functions to fill autocomplete AND to click specific locations */
function initAutocomplete() {
    // Create the autocomplete object, restricting the search to geographical
    autocomplete = new google.maps.places.Autocomplete((document.getElementById('street')),
        {types: ['geocode']});
    //autocomplete.addListener('place_changed', fillInAddress);
}<|endoftext|>


<commit_before>var tooltipIdeology = $("

").addClass("d3-tip").css("visibility","hidden").attr("id","tooltipIdeology").appendTo(document.body);

// From stackoverflow response, who borrowed it from Shopify--simple ordinal suffix.
var myLat, myLong;
var slowTimer;
var globalEnableLocation = 0;

function getGetOrdinal(n) {
    var s=["th","st","nd","rd"],
    v=n%100;
    return n+(s[(v-20)%10]||s[v]||s[0]);
 }

function congToYears(n) { return [1787+(2*n), 1787+(2*n)+2]; }

function lzPad(t)
{
	if(parseInt(t)<10) { return "0"+t; }
	else { return t; }
}

function loadText(t)
{
	$("#addressInput").val(t);
	latLongWrapper();
}

function resetResults()
{
	$("#resultsMembers").hide().html("");
	$("#addressCorrected").html("");
	$("#google_map").html("");
	$("#warnings").hide().html("");
	$("#loadProgress").hide().html("");
	$("#perm_link_holder").html("");
}

	$(document).ready(function(){
		$("#addressInput").on("focus",function() {
			if($("#addressInput").val()=="MY LOCATION") { $("#addressInput").val(""); }
		});
		$("#submit-address-form").submit(function(event)
		{
			event.preventDefault();
			latLongWrapper();
		});
		$("#submit-geolocation").click(function(event)
		{
			event.preventDefault();
			getLocation();
		});
		if($("#cachedLat").val()) { myLat = $("#cachedLat").val(); }
		if($("#cachedLong").val()) { myLong = $("#cachedLong").val(); }
		if($("#addressInput").val()) { setTimeout(function(){latLongWrapper();},1000); }
  	        $("ul#testData li").on("click",function(){ console.log($(this).val()); loadText(this.innerHTML); });
		$("ul#notableExamples li").on("click",function(){ console.log($(this).val()); loadText(this.innerHTML); });
	});

	if(navigator.geolocation)
	{
		globalEnableLocation=1;
		console.log('html5 location support.');
		$("#locationButton").show();
		function success(position)
		{
			clearTimeout(slowTimer);
			console.log(position.coords);
			myLat = position.coords.latitude;
			myLong = position.coords.longitude;
			$("#cachedLat").val(myLat);
			$("#cachedLong").val(myLong);
			$("#addressInput").val("MY LOCATION");
			resetResults();
			$("#loadProgress").show().html("Loading... Location matched, looking up historical representatives... ");
			doMembers(myLat, myLong);
		}
		function error()
		{
			clearTimeout(slowTimer);
			resetResults();
			$("#warnings").html("").show();
			var errorDiv = $("

").addClass("alert alert-danger").html("Error: Error looking up your location. Most commonly this occurs because you are having internet connection trouble or you have privacy settings designed to block web access to your location.");
			errorDiv.appendTo($("#warnings"));

			return;
		}
		function getLocation(event)
		{
			console.log(event);
			console.log('I AM HERE, IN THE GETLOCATION FUNCTION');
			resetResults();
			$("#loadProgress").show().html("Loading... Looking up your current location... ");
			slowTimer = setTimeout(function() { $("#loadProgress").html($("#loadProgress").html()+"
This process seems to be taking an unusually long time to complete. The delay is related to your internet connection, router, or web browser and is not connected to our server."); }, 5000);
			navigator.geolocation.getCurrentPosition(success, error);
		}
		$("#geolocationTutorial").show();
	}

	function latLongWrapper()
	{
		console.log('I AM HERE, IN THE ADDRESS LOOKUP.');
		resetResults();
		if($("#addressInput").val()=="")
		{
			$("#warnings").html("").show();
			var errorDiv = $("

").addClass("alert alert-danger").html("Error: No address specified.");
			errorDiv.appendTo($("#warnings"));
			return;
		}
		else if($("#addressInput").val()=="MY LOCATION" && globalEnableLocation && $("#cachedLat").val() && $("#cachedLong").val()) { doMembers(parseFloat($("#cachedLat").val()), parseFloat($("#cachedLong").val())); }
		else if($("#addressInput").val()=="MY LOCATION")
		{
			$("#warnings").html("").show();
			var errorDiv = $("

").addClass("alert alert-danger").html("Error: Error accessing your location, either due to internet connectivity or privacy settings. Please manually type an address to continue.");
			errorDiv.appendTo($("#warnings"));
		}
		else
		{
			$("#loadProgress").show().html("Loading... Matching address to map coordinates... ");
			setTimeout(doLatLong, 20);
		}
	}

	function doLatLong()
	{
		console.log('I AM HERE, CACHED LAT LONG TO DISTRICT LOOKUP.');
		$.ajax({
			dataType: "JSON",
			url: "/api/geocode?q="+$("#addressInput").val(),
			success: function(data, status, xhr)
			{
				console.log(data);
				if(data["status"])
				{
					$("#loadProgress").fadeOut();
					console.log("Error! Oh no!");
					var errorDiv = $("

").addClass("alert alert-danger").html("Error: "+data["error_message"])
					errorDiv.appendTo($("#warnings"));
					$("#warnings").fadeIn();
					return;
				}
				else
				{
					console.log(data);
					if(data["warnings"]!=undefined && data["warnings"].length)
					{
						$("#warnings").html("");
						var warningDiv = $("

").addClass("alert alert-warning").html("Warning: "+data["warnings"][0]);
						warningDiv.appendTo($("#warnings"));
						$("#warnings").fadeIn();
					}
					$("#addressCorrected").html("Address Lookup:
"+data["formatted_address"]+"");
					$("#loadProgress").html("Loading... Address matched, looking up historical representatives... ");
					doMembers(data["lat"], data["lng"]);
				}
			}
		});
	}

	function compareSort(a, b)
	{
		if(a.congress > b.congress) { return -1; }
		else if(a.congress < b.congress) { return 1; }
		else
		{
			if(a.party_noun  b.party_noun) { return 1; }
			else
			{
				if(a.bioname < b.bioname) { return -1; }
				else { return 1; }
			}
		}
	}

	function doMembers(lat, lng)
	{
		console.log("Entering this now.");
		console.log(lat);
		console.log(lng);
 		var markerPos = {lat: lat, lng: lng};
	    var map = new google.maps.Map(document.getElementById("google_map"), {zoom: 12, center: markerPos, disableDefaultUI: true, scrollwheel: false, draggable: true, zoomControl: true});
		var market = new google.maps.Marker({position: markerPos, map: map});

		$.ajax({
			dataType: "JSON",
			url: "/api/districtLookup?lat="+lat+"&long="+lng,
			success: function(data, status, xhr)
			{
				$("#loadProgress").fadeOut();
				if(data["resCurr"].length)
				{
					$("
Current Congressperson and Senators
").appendTo("#resultsMembers");
					var memberList = $("

").css("columns","auto 3")
								.css("list-style-type","none").css("overflow","auto")
								.css("width","100%").css("margin-left",0).css("padding-left",0).css("margin-bottom","15px")
								.css("display","block").attr("id","memberList");
				        console.log(data["resCurr"]);
					memberList.appendTo("#resultsMembers");
					$.each(data["resCurr"], function(k,v)
					{
						constructPlot(v, 0);
					});
				}

				var permLink = $("").attr("href","/district/"+encodeURI($("#addressInput").val())).html("Permanent Link to this address search.");
				permLink.appendTo($("#perm_link_holder"));

				$("
Historical Representatives
").appendTo("#resultsMembers");
				var table = $("

Congress	District	Ideology	Party	Member

")
						.addClass("table table-hover dc-data-table");
				var tbody = $("

");

				// For visual design, we do a pocket algorithm; save the last guy, compare to current guy, see what's changed.
				var lastResult = {};
				var myResults = data["results"].sort(compareSort);
				$.each(myResults, function(k, v)
				{
					// Check to see if we have other members at the same time
					var multiMember=0;
					if(v["congress"]<90)
					{
						var howMany = $.grep(myResults, function(n,i) { return (n["congress"]==v["congress"]); });
						if(howMany.length>1) { multiMember=1; }
					}

					// Explainers for weird edge cases (partition/joining or the Civil War)
					if(lastResult["congress"]>38 && lastResult["congress"]<=45 && v["congress"]<37 && v["congress"]>=30)
					{
						var civilWarDiv = $("

").addClass("alert alert-info").html("United States Civil War: "+v["state"]+" does not seat a delegation in the US Congress.");
						var tr = $("

");
						var td = $("	");
						civilWarDiv.appendTo(td);
						td.appendTo(tr);
						tr.appendTo(tbody);
					}
					if(lastResult["state"]=="Maryland" && Math.abs(v["congress"]-lastResult["congress"])>20)
					{
						var maryDiv = $("

").addClass("alert alert-info").html("D.C.: The changing shapes of congressional districts occasionally include the address you entered in Maryland. As above, Voteview.com does not track D.C. delegates.");
						var tr = $("

");
						var td = $("	");
						maryDiv.appendTo(td);
						td.appendTo(tr);
						tr.appendTo(tbody);
					}
					if(lastResult["state"]=="West Virginia" && v["state"]=="Virginia")
					{
						var virgDiv = $("

").addClass("alert alert-info").html("United States Civil War: West Virginia breaks away from Virginia to form a new state.");
						var tr = $("

");
						var td = $("	");
						virgDiv.appendTo(td);
						td.appendTo(tr);
						tr.appendTo(tbody);
					}
					if(lastResult["state"]=="Maine" && v["state"]=="Massachusetts")
					{
						var maineDiv = $("

").addClass("alert alert-info").html("1820: Maine votes to secede from Massachusetts and is admitted to the union as a state.");
						var tr = $("

");
						var td = $("	");
						maineDiv.appendTo(td);
						td.appendTo(tr);
						tr.appendTo(tbody);
					}

					var tr = $("

").on("click",function(){window.location='/person/'+v["icpsr"]+"/"+v["seo_name"];});
					dateSet = congToYears(v["congress"]);

					if(v["nominate"]!=undefined && v["nominate"]["dim1"]!=undefined) { var nomOffset = Math.floor((v["nominate"]["dim1"]+1.01)*50); }

					$(""+getGetOrdinal(v["congress"])+" ("+dateSet[0]+"-"+dateSet[1].toString().substr(2,2)+")	").appendTo(tr);
					$(""+v["state_abbrev"]+"-"+lzPad(v["district_code"])+"	").appendTo(tr);
					if(v["nominate"]!=undefined && v["nominate"]["dim1"]!=undefined)
					{
						var nomDiv = $("").css("border-right","3px solid "+colorSchemes[v["party_color"]][0])
										.css("width",nomOffset+"%").css("height","100%").css("overflow","auto").css("display","block");

						var holdingTD = $("	").css("padding","0").css("width","20px").css("border-left","1px solid grey").css("border-right","1px solid grey");
						nomDiv.appendTo(holdingTD);
						holdingTD.appendTo(tr);
					}
					else
					{
						$("	").appendTo(tr);
					}
					$(""+v["party_noun"]+"	").appendTo(tr);
					$(""+v["bioname"]+"	").appendTo(tr);

					// Use a closure to pin tooltips onto each row.
					(function(v){
						tr.on("mouseover", function()
						{
							$("#tooltipIdeology").html("");
							if(v["nominate"]!=undefined) { $("#tooltipIdeology").html(v["nominate"]["dim1"]); }
							else { $("#tooltipIdeology").html("No Ideology Score"); }

							$("#tooltipIdeology").removeClass().addClass("d3-tip");
							$("#tooltipIdeology").css("left",($(this).offset().left+245)+"px");
							$("#tooltipIdeology").css("top",$(this).offset().top+"px");
							$("#tooltipIdeology").css("visibility","visible");
						});
						tr.on("mouseout",function() { $("#tooltipIdeology").css("visibility","hidden"); });
					})(v);

					tr.appendTo(tbody);

					lastResult = v;
				});
				tbody.appendTo(table);
				table.appendTo($("#resultsMembers"));
				//permLink.appendTo($("#resultsMembers"));
				$("#resultsMembers").fadeIn();
			}
		});
	}

<commit_msg>Started on dynamic district search updating through lat/long, but not ready yet.<commit_after>var tooltipIdeology = $("

").addClass("d3-tip").css("visibility","hidden").attr("id","tooltipIdeology").appendTo(document.body);

// From stackoverflow response, who borrowed it from Shopify--simple ordinal suffix.
var myLat, myLong;
var slowTimer;
var globalEnableLocation = 0;

function getGetOrdinal(n) {
    var s=["th","st","nd","rd"],
    v=n%100;
    return n+(s[(v-20)%10]||s[v]||s[0]);
 }

function congToYears(n) { return [1787+(2*n), 1787+(2*n)+2]; }

function lzPad(t)
{
	if(parseInt(t)<10) { return "0"+t; }
	else { return t; }
}

function loadText(t)
{
	$("#addressInput").val(t);
	latLongWrapper();
}

function resetResults()
{
	$("#resultsMembers").hide().html("");
	$("#addressCorrected").html("");
	$("#google_map").html("");
	$("#warnings").hide().html("");
	$("#loadProgress").hide().html("");
	$("#perm_link_holder").html("");
}

	$(document).ready(function(){
		$("#addressInput").on("focus",function() {
			if($("#addressInput").val()=="MY LOCATION") { $("#addressInput").val(""); }
		});
		$("#submit-address-form").submit(function(event)
		{
			event.preventDefault();
			latLongWrapper();
		});
		$("#submit-geolocation").click(function(event)
		{
			event.preventDefault();
			getLocation();
		});
		if($("#cachedLat").val()) { myLat = $("#cachedLat").val(); }
		if($("#cachedLong").val()) { myLong = $("#cachedLong").val(); }
		if($("#addressInput").val()) { setTimeout(function(){latLongWrapper();},1000); }
  	        $("ul#testData li").on("click",function(){ console.log($(this).val()); loadText(this.innerHTML); });
		$("ul#notableExamples li").on("click",function(){ console.log($(this).val()); loadText(this.innerHTML); });
	});

	if(navigator.geolocation)
	{
		globalEnableLocation=1;
		console.log('html5 location support.');
		$("#locationButton").show();
		function success(position)
		{
			clearTimeout(slowTimer);
			console.log(position.coords);
			myLat = position.coords.latitude;
			myLong = position.coords.longitude;
			$("#cachedLat").val(myLat);
			$("#cachedLong").val(myLong);
			$("#addressInput").val("MY LOCATION");
			resetResults();
			$("#loadProgress").show().html("Loading... Location matched, looking up historical representatives... ");
			doMembers(myLat, myLong);
		}
		function error()
		{
			clearTimeout(slowTimer);
			resetResults();
			$("#warnings").html("").show();
			var errorDiv = $("

").addClass("alert alert-danger").html("Error: Error looking up your location. Most commonly this occurs because you are having internet connection trouble or you have privacy settings designed to block web access to your location.");
			errorDiv.appendTo($("#warnings"));

			return;
		}
		function getLocation(event)
		{
			console.log(event);
			console.log('I AM HERE, IN THE GETLOCATION FUNCTION');
			resetResults();
			$("#loadProgress").show().html("Loading... Looking up your current location... ");
			slowTimer = setTimeout(function() { $("#loadProgress").html($("#loadProgress").html()+"
This process seems to be taking an unusually long time to complete. The delay is related to your internet connection, router, or web browser and is not connected to our server."); }, 5000);
			navigator.geolocation.getCurrentPosition(success, error);
		}
		$("#geolocationTutorial").show();
	}

	function latLongWrapper()
	{
		console.log('I AM HERE, IN THE ADDRESS LOOKUP.');
		resetResults();
		if($("#addressInput").val()=="")
		{
			$("#warnings").html("").show();
			var errorDiv = $("

").addClass("alert alert-danger").html("Error: No address specified.");
			errorDiv.appendTo($("#warnings"));
			return;
		}
		else if($("#addressInput").val()=="MY LOCATION" && globalEnableLocation && $("#cachedLat").val() && $("#cachedLong").val()) { doMembers(parseFloat($("#cachedLat").val()), parseFloat($("#cachedLong").val())); }
		else if($("#addressInput").val()=="MY LOCATION")
		{
			$("#warnings").html("").show();
			var errorDiv = $("

").addClass("alert alert-danger").html("Error: Error accessing your location, either due to internet connectivity or privacy settings. Please manually type an address to continue.");
			errorDiv.appendTo($("#warnings"));
		}
		else
		{
			$("#loadProgress").show().html("Loading... Matching address to map coordinates... ");
			setTimeout(doLatLong, 20);
		}
	}

	function doLatLong()
	{
		console.log('I AM HERE, CACHED LAT LONG TO DISTRICT LOOKUP.');
		$.ajax({
			dataType: "JSON",
			url: "/api/geocode?q="+$("#addressInput").val(),
			success: function(data, status, xhr)
			{
				console.log(data);
				if(data["status"])
				{
					$("#loadProgress").fadeOut();
					console.log("Error! Oh no!");
					var errorDiv = $("

").addClass("alert alert-danger").html("Error: "+data["error_message"])
					errorDiv.appendTo($("#warnings"));
					$("#warnings").fadeIn();
					return;
				}
				else
				{
					console.log(data);
					if(data["warnings"]!=undefined && data["warnings"].length)
					{
						$("#warnings").html("");
						var warningDiv = $("

").addClass("alert alert-warning").html("Warning: "+data["warnings"][0]);
						warningDiv.appendTo($("#warnings"));
						$("#warnings").fadeIn();
					}
					$("#addressCorrected").html("Address Lookup:
"+data["formatted_address"]+"");
					$("#loadProgress").html("Loading... Address matched, looking up historical representatives... ");
					doMembers(data["lat"], data["lng"]);
				}
			}
		});
	}

	function compareSort(a, b)
	{
		if(a.congress > b.congress) { return -1; }
		else if(a.congress < b.congress) { return 1; }
		else
		{
			if(a.party_noun  b.party_noun) { return 1; }
			else
			{
				if(a.bioname < b.bioname) { return -1; }
				else { return 1; }
			}
		}
	}

	function doMembers(lat, lng)
	{
		console.log("Entering this now.");
		console.log(lat);
		console.log(lng);
 		var markerPos = {lat: lat, lng: lng};
		var map = new google.maps.Map(document.getElementById("google_map"), {zoom: 12, center: markerPos, disableDefaultUI: true, scrollwheel: false, draggable: true, zoomControl: true});
		// Put the marker in the lat/long
		var marker = new google.maps.Marker({position: markerPos, map: map});
		// If the user moves the viewport, update the map?
		google.maps.event.addListener(map, 'idle', function()
		{
			console.log("idle now");
			var coords = [map.getCenter().lat(), map.getCenter().lng()];
			//$("#addressInput").val(coords[0]+", "+coords[1]);
			//resetResults();
			//doLatLong();
		});

		$.ajax({
			dataType: "JSON",
			url: "/api/districtLookup?lat="+lat+"&long="+lng,
			success: function(data, status, xhr)
			{
				$("#loadProgress").fadeOut();
				if(data["resCurr"].length)
				{
					$("
Current Congressperson and Senators
").appendTo("#resultsMembers");
					var memberList = $("

").css("columns","auto 3")
								.css("list-style-type","none").css("overflow","auto")
								.css("width","100%").css("margin-left",0).css("padding-left",0).css("margin-bottom","15px")
								.css("display","block").attr("id","memberList");
				        console.log(data["resCurr"]);
					memberList.appendTo("#resultsMembers");
					$.each(data["resCurr"], function(k,v)
					{
						constructPlot(v, 0);
					});
				}

				var permLink = $("").attr("href","/district/"+encodeURI($("#addressInput").val())).html("Permanent Link to this address search.");
				permLink.appendTo($("#perm_link_holder"));

				$("
Historical Representatives
").appendTo("#resultsMembers");
				var table = $("

Congress	District	Ideology	Party	Member

")
						.addClass("table table-hover dc-data-table");
				var tbody = $("

");

				// For visual design, we do a pocket algorithm; save the last guy, compare to current guy, see what's changed.
				var lastResult = {};
				var myResults = data["results"].sort(compareSort);
				$.each(myResults, function(k, v)
				{
					// Check to see if we have other members at the same time
					var multiMember=0;
					if(v["congress"]<90)
					{
						var howMany = $.grep(myResults, function(n,i) { return (n["congress"]==v["congress"]); });
						if(howMany.length>1) { multiMember=1; }
					}

					// Explainers for weird edge cases (partition/joining or the Civil War)
					if(lastResult["congress"]>38 && lastResult["congress"]<=45 && v["congress"]<37 && v["congress"]>=30)
					{
						var civilWarDiv = $("

").addClass("alert alert-info").html("United States Civil War: "+v["state"]+" does not seat a delegation in the US Congress.");
						var tr = $("

");
						var td = $("	");
						civilWarDiv.appendTo(td);
						td.appendTo(tr);
						tr.appendTo(tbody);
					}
					if(lastResult["state"]=="Maryland" && Math.abs(v["congress"]-lastResult["congress"])>20)
					{
						var maryDiv = $("

").addClass("alert alert-info").html("D.C.: The changing shapes of congressional districts occasionally include the address you entered in Maryland. As above, Voteview.com does not track D.C. delegates.");
						var tr = $("

");
						var td = $("	");
						maryDiv.appendTo(td);
						td.appendTo(tr);
						tr.appendTo(tbody);
					}
					if(lastResult["state"]=="West Virginia" && v["state"]=="Virginia")
					{
						var virgDiv = $("

").addClass("alert alert-info").html("United States Civil War: West Virginia breaks away from Virginia to form a new state.");
						var tr = $("

");
						var td = $("	");
						virgDiv.appendTo(td);
						td.appendTo(tr);
						tr.appendTo(tbody);
					}
					if(lastResult["state"]=="Maine" && v["state"]=="Massachusetts")
					{
						var maineDiv = $("

").addClass("alert alert-info").html("1820: Maine votes to secede from Massachusetts and is admitted to the union as a state.");
						var tr = $("

");
						var td = $("	");
						maineDiv.appendTo(td);
						td.appendTo(tr);
						tr.appendTo(tbody);
					}

					var tr = $("

").on("click",function(){window.location='/person/'+v["icpsr"]+"/"+v["seo_name"];});
					dateSet = congToYears(v["congress"]);

					if(v["nominate"]!=undefined && v["nominate"]["dim1"]!=undefined) { var nomOffset = Math.floor((v["nominate"]["dim1"]+1.01)*50); }

					$(""+getGetOrdinal(v["congress"])+" ("+dateSet[0]+"-"+dateSet[1].toString().substr(2,2)+")	").appendTo(tr);
					$(""+v["state_abbrev"]+"-"+lzPad(v["district_code"])+"	").appendTo(tr);
					if(v["nominate"]!=undefined && v["nominate"]["dim1"]!=undefined)
					{
						var nomDiv = $("").css("border-right","3px solid "+colorSchemes[v["party_color"]][0])
										.css("width",nomOffset+"%").css("height","100%").css("overflow","auto").css("display","block");

						var holdingTD = $("	").css("padding","0").css("width","20px").css("border-left","1px solid grey").css("border-right","1px solid grey");
						nomDiv.appendTo(holdingTD);
						holdingTD.appendTo(tr);
					}
					else
					{
						$("	").appendTo(tr);
					}
					$(""+v["party_noun"]+"	").appendTo(tr);
					$(""+v["bioname"]+"	").appendTo(tr);

					// Use a closure to pin tooltips onto each row.
					(function(v){
						tr.on("mouseover", function()
						{
							$("#tooltipIdeology").html("");
							if(v["nominate"]!=undefined) { $("#tooltipIdeology").html(v["nominate"]["dim1"]); }
							else { $("#tooltipIdeology").html("No Ideology Score"); }

							$("#tooltipIdeology").removeClass().addClass("d3-tip");
							$("#tooltipIdeology").css("left",($(this).offset().left+245)+"px");
							$("#tooltipIdeology").css("top",$(this).offset().top+"px");
							$("#tooltipIdeology").css("visibility","visible");
						});
						tr.on("mouseout",function() { $("#tooltipIdeology").css("visibility","hidden"); });
					})(v);

					tr.appendTo(tbody);

					lastResult = v;
				});
				tbody.appendTo(table);
				table.appendTo($("#resultsMembers"));
				//permLink.appendTo($("#resultsMembers"));
				$("#resultsMembers").fadeIn();
			}
		});
	}

<|endoftext|>