<commit_before>//= require jquery3
//= require jquery_ujs
//= require turbolinks
//= require local-time
//= require popper
//= require bootstrap/util
//= require bootstrap/collapse
//= require bootstrap/alert
//= require bootstrap/tooltip
//= require bootstrap/dropdown
//= require bootstrap/modal
//= require_tree .

function getDisplayedRows() {
  return $(".js-table-notifications tr.notification")
}

// gets all marked rows (or unmarked rows if unmarked is true)
function getMarkedRows(unmarked) {
  return unmarked ? getDisplayedRows().has("input:not(:checked)") : getDisplayedRows().has("input:checked")
}

function getIdsFromRows(rows) {
  return $('button.select_all').hasClass('all_selected') ?
    'all' : $.map(rows, function(row) {return $(row).find("input").val()})
}

// returns true if there are any marked rows (or unmarked rows if unmarked is true)
function hasMarkedRows(unmarked) {
  return getMarkedRows(unmarked).length > 0
}

function getCurrentRow() {
  return getDisplayedRows().has('td.js-current')
}

function getMarkedOrCurrentRows() {
  return hasMarkedRows() ? getMarkedRows() : getCurrentRow()
}

function moveCursorToClickedRow(event) {
  // Don't event.preventDefault(), since we want the normal clicking behavior for links, starring, etc
  var oldCurrent = getCurrentRow();
  var target = $(this);
  setRowCurrent(oldCurrent, false);
  setRowCurrent(target, true);
}

var unread_count = 0;

function updateFavicon() {
  $.get( "/notifications/unread_count", function(data) {
    if (data["count"] !== unread_count) {
      unread_count = data["count"]

      var title = 'Octobox';
      if (unread_count > 0) {
        title += ' (' + unread_count +')';
      }
      window.document.title = title;

      var old_link = document.getElementById('favicon-count');
      if ( old_link ) {
        $(old_link).remove();
      }

      var canvas = document.createElement('canvas'),
        ctx,
        img = document.createElement('img'),
        link = document.getElementById('favicon').cloneNode(true),
        txt = unread_count + '';

      link.id = "favicon-count";

      if (canvas.getContext) {
        canvas.height = canvas.width = 32;
        ctx = canvas.getContext('2d');

          img.onload = function () {
            ctx.drawImage(this, 0, 0);

            if (unread_count > 0){
              ctx.fillStyle = '#f93e00';
              ctx.font = 'bold 20px "helvetica", sans-serif';

              var width = ctx.measureText(txt).width;
              ctx.fillRect(0, 0, width+4, 24);

              ctx.fillStyle = '#fff';
              ctx.fillText(txt, 2, 20);
            }

            link.href = canvas.toDataURL('image/png');
            document.body.appendChild(link);
          };

        img.src = "/favicon-32x32.png";
      }
    }
  });
}

document.addEventListener("turbolinks:load", function() {
  enableKeyboardShortcuts();

  if($(".js-initial_sync").length){ sync() }

  if($("#help-box").length){
    $('button.archive_selected, button.unarchive_selected').click(toggleArchive);
    $('button.select_all').click(toggleSelectAll);
    $('button.mute_selected').click(mute);
    $('button.mark_read_selected').click(markReadSelected);
    $('tr.notification').click(moveCursorToClickedRow);

    $('input.archive, input.unarchive').change(function() {
      if ( hasMarkedRows() ) {
        $('button.archive_selected, button.unarchive_selected, button.mute_selected').show().css("display", "inline-block");
        if ( !hasMarkedRows(true) ) {
          $(".js-select_all").prop('checked', true).prop('indeterminate', false);
          $('button.select_all').show().css("display", "inline-block");
        } else {
          $(".js-select_all").prop('checked', false).prop('indeterminate', true);
          $('button.select_all').hide();
        }
      } else {
        $(".js-select_all").prop('checked', false).prop('indeterminate', false);
        $('button.archive_selected, button.unarchive_selected, button.mute_selected, button.select_all').hide();
      }
      var marked_unread_length = getMarkedRows().filter('.active').length;
      if ( marked_unread_length > 0 ) {
        $('button.mark_read_selected').show().css("display", "inline-block");
      } else {
        $('button.mark_read_selected').hide();
      }
    });
    $('.toggle-star').click(function() {
      $(this).toggleClass("star-active star-inactive");
      $.post('/notifications/'+$(this).data('id')+'/star')
    });
    recoverPreviousCursorPosition();

    $('.js-select_all').change(function() {
      checkAll($(".js-select_all").prop('checked'))
    })

    enableTooltips();

    updateFavicon();
  }
});

$(document).ready(enableTooltips);

document.addEventListener("turbolinks:before-cache", function() {
  $('td.js-current').removeClass("current js-current");
});

$(document).on('click', '[data-toggle="offcanvas"]', function () {
  $('.flex-content').toggleClass('active')
});

$(document).on('click', 'a.js-sync', function(e) {
  e.preventDefault(e);
  sync()
});

function enableTooltips() {
  if(!('ontouchstart' in window))
  {
    $('[data-toggle="tooltip"]').tooltip()
  }
}

function enableKeyboardShortcuts() {
  // Add shortcut events only once
  if (window.row_index !== undefined) return;

  window.row_index = 1;
  window.current_id = undefined;

  $(document).keydown(function(e) {
    // disable shortcuts for the seach box
    if (e.target.id !== 'search-box') {
      var shortcutFunction = shortcuts[e.which];
      if (shortcutFunction) { shortcutFunction(e) }
    }
  });
}

var shortcuts = {
  65:  checkSelectAll,    // a
  68:  markReadSelected,  // d
  74:  cursorDown,        // j
  75:  cursorUp,          // k
  83:  toggleStar,        // s
  88:  markCurrent,       // x
  89:  toggleArchive,     // y
  69:  toggleArchive,     // e
  77:  mute,              // m
  13:  openCurrentLink,   // Enter
  79:  openCurrentLink,   // o
  191: openModal,         // ?
  190: sync,              // .
  82:  sync,              // r
  27:  escPressed,        // esc
};

function cursorDown() {
  moveCursor('up')
}

function cursorUp() {
  moveCursor('down')
}

function markCurrent() {
  getCurrentRow().find("input[type=checkbox]").click();
}

function checkAll(checked) {
  getDisplayedRows().find('input').prop("checked", checked).trigger('change');
}

function checkSelectAll() {
  $(".js-select_all").click()
}

function mute() {
  if (getDisplayedRows().length === 0) return;
  if ( $(".js-table-notifications tr").length === 0 ) return;
  var ids = getIdsFromRows(getMarkedOrCurrentRows());
  $.post( "/notifications/mute_selected" + location.search, { 'id[]': ids}).done(function() {resetCursorAfterRowsRemoved(ids)});
}

function markReadSelected() {
  if (getDisplayedRows().length === 0) return;
  var rows = getMarkedOrCurrentRows();
  rows.addClass('blur-action');
  $.post("/notifications/mark_read_selected" + location.search, {'id[]': getIdsFromRows(rows)}).done(function () {
    rows.removeClass('blur-action')
    rows.removeClass('active');
    updateFavicon();
  })
}

function markRead(id) {
  $.post( "/notifications/"+id+"/mark_read").done(function() {
    updateFavicon();
  });
  $('#notification-'+id).removeClass('active');
}

function toggleArchive() {
  if (getDisplayedRows().length === 0) return;

  var cssClass, value;

  if ( $(".archive_toggle").hasClass("archive_selected") ) {
    cssClass = '.archive'
    value = true
  } else {
    cssClass = '.unarchive'
    value = false
  }

  var ids = getIdsFromRows(getMarkedOrCurrentRows());

  $.post( "/notifications/archive_selected" + location.search, { 'id[]': ids, 'value': value } ).done(function() {resetCursorAfterRowsRemoved(ids)});
}

function toggleSelectAll() {
  $.map($('button.select_all > span'), function( val, i ) {
    $(val).toggleClass('bold')
  });
  $('button.select_all').toggleClass('all_selected')
}

function resetCursorAfterRowsRemoved(ids) {
  var current = getCurrentRow();
  while ( $.inArray(getIdsFromRows(current)[0], ids) > -1 && current.next().length > 0) {
    current = current.next();
  }
  while ( $.inArray(getIdsFromRows(current)[0], ids) > -1 && current.prev().length > 0) {
    current = current.prev();
  }

  window.current_id = getIdsFromRows(current)[0];
  Turbolinks.visit("/"+location.search);
}

function toggleStar() {
  getCurrentRow().find('.toggle-star').click();
}

function openModal() {
  $("#help-box").modal({ keyboard: false });
}

function openCurrentLink(e) {
  e.preventDefault(e);
  getCurrentRow().find('td.notification-subject .link')[0].click();
}

function refreshOnSync() {
  if(!$(".js-sync .octicon").hasClass("spinning")){
    $(".js-sync .octicon").addClass("spinning");
  }

  jQuery.ajax({'url': "/notifications/syncing.json", data: {}, error: function(xhr, status) {
      setTimeout(refreshOnSync, 2000)
    }, success: function(data, status, xhr) {
      if (data['error'] != null) {
        $(".sync .octicon").removeClass("spinning");
        $(".header-flash-messages").empty();
        notify(data['error'], 'danger')
      } else {
        Turbolinks.visit("/"+location.search);
      }
    }
  });
}

function notify(message, type) {
  var alert_html = [
    "
",
    "   <button class='close' data-dismiss='alert'>x</button>",
    message,
    "
"
  ].join("\n");
  $(".header-flash-messages").append(alert_html);
}

function sync() {
  if($("a.js-sync.js-async").length) {
    $.get('/notifications/sync.json', refreshOnSync);
  } else {
    Turbolinks.visit($("a.js-sync").attr('href'))
  }
}

function autoSync() {
  hasMarkedRows() || sync()
}

function escPressed(e) {
  if ($("#help-box").is(':visible')) {
    $("#help-box").modal('hide');
  } else {
    clearFilters();
  }
}

function clearFilters() {
  Turbolinks.visit("/");
}

function setAutoSyncTimer() {
  var refresh_interval = $('.js-table-notifications').data('refresh-interval');
  if (isNaN(refresh_interval)) return;
  refresh_interval > 0 && setInterval(autoSync, refresh_interval)
}

$(document).ready(setAutoSyncTimer);

function scrollToCursor() {
  var current = $('td.js-current');
  var table_offset = $('.js-table-notifications').position().top;
  var cursor_offset = current.offset().top;
  var cursor_relative_offset = current.position().top;
  var cursor_height = current.height();
  var menu_height = $(".js-octobox-menu").height();
  var scroll_top = $(document).scrollTop();
  var window_height = $(window).height();
  if ( cursor_offset < menu_height + scroll_top ) {
    $("html, body").animate({
      scrollTop: table_offset + cursor_relative_offset - cursor_height
    }, 0);
  }
  if ( cursor_offset > scroll_top + window_height - cursor_height ) {
    $("html, body").animate({
      scrollTop: cursor_offset - window_height + 2*cursor_height
    }, 0);
  }
}

function setRowCurrent(row, add) {
  var classes = 'current js-current';
  var td = row.find('td.notification-checkbox');
  add ? td.addClass(classes) : td.removeClass(classes)
}

function moveCursor(upOrDown) {
  var oldCurrent = getCurrentRow();
  var target = upOrDown === 'up' ? oldCurrent.next() : oldCurrent.prev();
  if(target.length > 0) {
    setRowCurrent(oldCurrent, false);
    setRowCurrent(target, true);
    scrollToCursor();
  }
}

function recoverPreviousCursorPosition() {
  if ( current_id === undefined ) {
    row_index = Math.min(row_index, $(".js-table-notifications tr").length);
    row_index = Math.max(row_index, 1);
  } else {
    row_index = $('#notification-'+current_id).index() + 1;
    current_id = undefined;
  }
  $(".js-table-notifications tbody tr:nth-child(" + row_index + ")").first().find("td").first().addClass("current js-current");
}

// Clicking a row marks it current
$(document).ready(function() {
  $("tr.notification").click(function() {
    $(".current.js-current").removeClass("current js-current");
    $( this ).find("td").first().addClass("current js-current");
  })
});

// Sync Handling
$(document).ready(function() {
  if($(".js-is_syncing").length){ refreshOnSync() }
  if($(".js-start_sync").length){ sync() }
});

var lastCheckedNotification = null;
// handle shift+click multiple check
$(document).ready(function() {
  var notificationCheckboxes = $('input.archive[type="checkbox"]');
  notificationCheckboxes.click(function(e) {
    if(!lastCheckedNotification) {
      lastCheckedNotification = this;
      return;
    }

    if(e.shiftKey) {
      var start = notificationCheckboxes.index(this);
      var end = notificationCheckboxes.index(lastCheckedNotification);

      notificationCheckboxes.slice(Math.min(start,end), Math.max(start,end)+ 1).prop('checked', lastCheckedNotification.checked);

    }

    lastCheckedNotification = this;
  });
});
<commit_msg>Don't fire keyboard shortcuts when ctrl/cmd/alt/shift held down (#997)<commit_after>//= require jquery3
//= require jquery_ujs
//= require turbolinks
//= require local-time
//= require popper
//= require bootstrap/util
//= require bootstrap/collapse
//= require bootstrap/alert
//= require bootstrap/tooltip
//= require bootstrap/dropdown
//= require bootstrap/modal
//= require_tree .

function getDisplayedRows() {
  return $(".js-table-notifications tr.notification")
}

// gets all marked rows (or unmarked rows if unmarked is true)
function getMarkedRows(unmarked) {
  return unmarked ? getDisplayedRows().has("input:not(:checked)") : getDisplayedRows().has("input:checked")
}

function getIdsFromRows(rows) {
  return $('button.select_all').hasClass('all_selected') ?
    'all' : $.map(rows, function(row) {return $(row).find("input").val()})
}

// returns true if there are any marked rows (or unmarked rows if unmarked is true)
function hasMarkedRows(unmarked) {
  return getMarkedRows(unmarked).length > 0
}

function getCurrentRow() {
  return getDisplayedRows().has('td.js-current')
}

function getMarkedOrCurrentRows() {
  return hasMarkedRows() ? getMarkedRows() : getCurrentRow()
}

function moveCursorToClickedRow(event) {
  // Don't event.preventDefault(), since we want the normal clicking behavior for links, starring, etc
  var oldCurrent = getCurrentRow();
  var target = $(this);
  setRowCurrent(oldCurrent, false);
  setRowCurrent(target, true);
}

var unread_count = 0;

function updateFavicon() {
  $.get( "/notifications/unread_count", function(data) {
    if (data["count"] !== unread_count) {
      unread_count = data["count"]

      var title = 'Octobox';
      if (unread_count > 0) {
        title += ' (' + unread_count +')';
      }
      window.document.title = title;

      var old_link = document.getElementById('favicon-count');
      if ( old_link ) {
        $(old_link).remove();
      }

      var canvas = document.createElement('canvas'),
        ctx,
        img = document.createElement('img'),
        link = document.getElementById('favicon').cloneNode(true),
        txt = unread_count + '';

      link.id = "favicon-count";

      if (canvas.getContext) {
        canvas.height = canvas.width = 32;
        ctx = canvas.getContext('2d');

          img.onload = function () {
            ctx.drawImage(this, 0, 0);

            if (unread_count > 0){
              ctx.fillStyle = '#f93e00';
              ctx.font = 'bold 20px "helvetica", sans-serif';

              var width = ctx.measureText(txt).width;
              ctx.fillRect(0, 0, width+4, 24);

              ctx.fillStyle = '#fff';
              ctx.fillText(txt, 2, 20);
            }

            link.href = canvas.toDataURL('image/png');
            document.body.appendChild(link);
          };

        img.src = "/favicon-32x32.png";
      }
    }
  });
}

document.addEventListener("turbolinks:load", function() {
  enableKeyboardShortcuts();

  if($(".js-initial_sync").length){ sync() }

  if($("#help-box").length){
    $('button.archive_selected, button.unarchive_selected').click(toggleArchive);
    $('button.select_all').click(toggleSelectAll);
    $('button.mute_selected').click(mute);
    $('button.mark_read_selected').click(markReadSelected);
    $('tr.notification').click(moveCursorToClickedRow);

    $('input.archive, input.unarchive').change(function() {
      if ( hasMarkedRows() ) {
        $('button.archive_selected, button.unarchive_selected, button.mute_selected').show().css("display", "inline-block");
        if ( !hasMarkedRows(true) ) {
          $(".js-select_all").prop('checked', true).prop('indeterminate', false);
          $('button.select_all').show().css("display", "inline-block");
        } else {
          $(".js-select_all").prop('checked', false).prop('indeterminate', true);
          $('button.select_all').hide();
        }
      } else {
        $(".js-select_all").prop('checked', false).prop('indeterminate', false);
        $('button.archive_selected, button.unarchive_selected, button.mute_selected, button.select_all').hide();
      }
      var marked_unread_length = getMarkedRows().filter('.active').length;
      if ( marked_unread_length > 0 ) {
        $('button.mark_read_selected').show().css("display", "inline-block");
      } else {
        $('button.mark_read_selected').hide();
      }
    });
    $('.toggle-star').click(function() {
      $(this).toggleClass("star-active star-inactive");
      $.post('/notifications/'+$(this).data('id')+'/star')
    });
    recoverPreviousCursorPosition();

    $('.js-select_all').change(function() {
      checkAll($(".js-select_all").prop('checked'))
    })

    enableTooltips();

    updateFavicon();
  }
});

$(document).ready(enableTooltips);

document.addEventListener("turbolinks:before-cache", function() {
  $('td.js-current').removeClass("current js-current");
});

$(document).on('click', '[data-toggle="offcanvas"]', function () {
  $('.flex-content').toggleClass('active')
});

$(document).on('click', 'a.js-sync', function(e) {
  e.preventDefault(e);
  sync()
});

function enableTooltips() {
  if(!('ontouchstart' in window))
  {
    $('[data-toggle="tooltip"]').tooltip()
  }
}

function enableKeyboardShortcuts() {
  // Add shortcut events only once
  if (window.row_index !== undefined) return;

  window.row_index = 1;
  window.current_id = undefined;

  $(document).keydown(function(e) {
    // disable shortcuts for the seach box
    if (e.target.id !== 'search-box' && !e.ctrlKey && !e.altKey  && !e.shiftKey && !e.metaKey) {
      var shortcutFunction = shortcuts[e.which];
      if (shortcutFunction) { shortcutFunction(e) }
    }
  });
}

var shortcuts = {
  65:  checkSelectAll,    // a
  68:  markReadSelected,  // d
  74:  cursorDown,        // j
  75:  cursorUp,          // k
  83:  toggleStar,        // s
  88:  markCurrent,       // x
  89:  toggleArchive,     // y
  69:  toggleArchive,     // e
  77:  mute,              // m
  13:  openCurrentLink,   // Enter
  79:  openCurrentLink,   // o
  191: openModal,         // ?
  190: sync,              // .
  82:  sync,              // r
  27:  escPressed,        // esc
};

function cursorDown() {
  moveCursor('up')
}

function cursorUp() {
  moveCursor('down')
}

function markCurrent() {
  getCurrentRow().find("input[type=checkbox]").click();
}

function checkAll(checked) {
  getDisplayedRows().find('input').prop("checked", checked).trigger('change');
}

function checkSelectAll() {
  $(".js-select_all").click()
}

function mute() {
  if (getDisplayedRows().length === 0) return;
  if ( $(".js-table-notifications tr").length === 0 ) return;
  var ids = getIdsFromRows(getMarkedOrCurrentRows());
  $.post( "/notifications/mute_selected" + location.search, { 'id[]': ids}).done(function() {resetCursorAfterRowsRemoved(ids)});
}

function markReadSelected() {
  if (getDisplayedRows().length === 0) return;
  var rows = getMarkedOrCurrentRows();
  rows.addClass('blur-action');
  $.post("/notifications/mark_read_selected" + location.search, {'id[]': getIdsFromRows(rows)}).done(function () {
    rows.removeClass('blur-action')
    rows.removeClass('active');
    updateFavicon();
  })
}

function markRead(id) {
  $.post( "/notifications/"+id+"/mark_read").done(function() {
    updateFavicon();
  });
  $('#notification-'+id).removeClass('active');
}

function toggleArchive() {
  if (getDisplayedRows().length === 0) return;

  var cssClass, value;

  if ( $(".archive_toggle").hasClass("archive_selected") ) {
    cssClass = '.archive'
    value = true
  } else {
    cssClass = '.unarchive'
    value = false
  }

  var ids = getIdsFromRows(getMarkedOrCurrentRows());

  $.post( "/notifications/archive_selected" + location.search, { 'id[]': ids, 'value': value } ).done(function() {resetCursorAfterRowsRemoved(ids)});
}

function toggleSelectAll() {
  $.map($('button.select_all > span'), function( val, i ) {
    $(val).toggleClass('bold')
  });
  $('button.select_all').toggleClass('all_selected')
}

function resetCursorAfterRowsRemoved(ids) {
  var current = getCurrentRow();
  while ( $.inArray(getIdsFromRows(current)[0], ids) > -1 && current.next().length > 0) {
    current = current.next();
  }
  while ( $.inArray(getIdsFromRows(current)[0], ids) > -1 && current.prev().length > 0) {
    current = current.prev();
  }

  window.current_id = getIdsFromRows(current)[0];
  Turbolinks.visit("/"+location.search);
}

function toggleStar() {
  getCurrentRow().find('.toggle-star').click();
}

function openModal() {
  $("#help-box").modal({ keyboard: false });
}

function openCurrentLink(e) {
  e.preventDefault(e);
  getCurrentRow().find('td.notification-subject .link')[0].click();
}

function refreshOnSync() {
  if(!$(".js-sync .octicon").hasClass("spinning")){
    $(".js-sync .octicon").addClass("spinning");
  }

  jQuery.ajax({'url': "/notifications/syncing.json", data: {}, error: function(xhr, status) {
      setTimeout(refreshOnSync, 2000)
    }, success: function(data, status, xhr) {
      if (data['error'] != null) {
        $(".sync .octicon").removeClass("spinning");
        $(".header-flash-messages").empty();
        notify(data['error'], 'danger')
      } else {
        Turbolinks.visit("/"+location.search);
      }
    }
  });
}

function notify(message, type) {
  var alert_html = [
    "
",
    "   <button class='close' data-dismiss='alert'>x</button>",
    message,
    "
"
  ].join("\n");
  $(".header-flash-messages").append(alert_html);
}

function sync() {
  if($("a.js-sync.js-async").length) {
    $.get('/notifications/sync.json', refreshOnSync);
  } else {
    Turbolinks.visit($("a.js-sync").attr('href'))
  }
}

function autoSync() {
  hasMarkedRows() || sync()
}

function escPressed(e) {
  if ($("#help-box").is(':visible')) {
    $("#help-box").modal('hide');
  } else {
    clearFilters();
  }
}

function clearFilters() {
  Turbolinks.visit("/");
}

function setAutoSyncTimer() {
  var refresh_interval = $('.js-table-notifications').data('refresh-interval');
  if (isNaN(refresh_interval)) return;
  refresh_interval > 0 && setInterval(autoSync, refresh_interval)
}

$(document).ready(setAutoSyncTimer);

function scrollToCursor() {
  var current = $('td.js-current');
  var table_offset = $('.js-table-notifications').position().top;
  var cursor_offset = current.offset().top;
  var cursor_relative_offset = current.position().top;
  var cursor_height = current.height();
  var menu_height = $(".js-octobox-menu").height();
  var scroll_top = $(document).scrollTop();
  var window_height = $(window).height();
  if ( cursor_offset < menu_height + scroll_top ) {
    $("html, body").animate({
      scrollTop: table_offset + cursor_relative_offset - cursor_height
    }, 0);
  }
  if ( cursor_offset > scroll_top + window_height - cursor_height ) {
    $("html, body").animate({
      scrollTop: cursor_offset - window_height + 2*cursor_height
    }, 0);
  }
}

function setRowCurrent(row, add) {
  var classes = 'current js-current';
  var td = row.find('td.notification-checkbox');
  add ? td.addClass(classes) : td.removeClass(classes)
}

function moveCursor(upOrDown) {
  var oldCurrent = getCurrentRow();
  var target = upOrDown === 'up' ? oldCurrent.next() : oldCurrent.prev();
  if(target.length > 0) {
    setRowCurrent(oldCurrent, false);
    setRowCurrent(target, true);
    scrollToCursor();
  }
}

function recoverPreviousCursorPosition() {
  if ( current_id === undefined ) {
    row_index = Math.min(row_index, $(".js-table-notifications tr").length);
    row_index = Math.max(row_index, 1);
  } else {
    row_index = $('#notification-'+current_id).index() + 1;
    current_id = undefined;
  }
  $(".js-table-notifications tbody tr:nth-child(" + row_index + ")").first().find("td").first().addClass("current js-current");
}

// Clicking a row marks it current
$(document).ready(function() {
  $("tr.notification").click(function() {
    $(".current.js-current").removeClass("current js-current");
    $( this ).find("td").first().addClass("current js-current");
  })
});

// Sync Handling
$(document).ready(function() {
  if($(".js-is_syncing").length){ refreshOnSync() }
  if($(".js-start_sync").length){ sync() }
});

var lastCheckedNotification = null;
// handle shift+click multiple check
$(document).ready(function() {
  var notificationCheckboxes = $('input.archive[type="checkbox"]');
  notificationCheckboxes.click(function(e) {
    if(!lastCheckedNotification) {
      lastCheckedNotification = this;
      return;
    }

    if(e.shiftKey) {
      var start = notificationCheckboxes.index(this);
      var end = notificationCheckboxes.index(lastCheckedNotification);

      notificationCheckboxes.slice(Math.min(start,end), Math.max(start,end)+ 1).prop('checked', lastCheckedNotification.checked);

    }

    lastCheckedNotification = this;
  });
});
<|endoftext|>


<commit_before>(function() {

    var formCheckValid = function(el) {
        var inputType = (el.tagName.toLowerCase() == 'textarea') ? 'textarea' : $(el).attr('type');

        switch (inputType) {
            case 'radio':
            case 'checkbox':
                return (el.checked) ? el.name : null;
                break;
            case 'text':
            case 'number':
            case 'textarea':
                var pattern = (pattern = $(el).attr('data-pattern')) ? pattern : $(el).attr('pattern');
                if (pattern != null) {
                    var result = $(el).val().match(new RegExp(pattern,"gi"));
                    return (result!= null && result.length > 0 && result[0] != '') ?el.name : null;
                } else {
                    return ($(el).val() != '') ? el.name : null;
                }
                break;
            default:
                return null;
        }
    };

    $(document).ready(function() {
        $('a.previousPage').each(function() {
            $(this).on('click', function() {
                if (!confirm('Are you sure you want to go back? You may lose form data.\n\nNB: We need to assess the need and functionality of this link')) {
                    return false;
                }
            });

        });

        /* display-none-js is a class that should only work to hide information when javascript is enabled */
        $('.display-none-js').hide();

        /* generic toggle functionality */
        $('.toggle-section').on('click', function() {
            var sections = $(this).parents('.form-group').attr('data-target');
            var sectionOn = $(this).parents('.form-group').attr('data-target') + '__' + $(this).val().toLowerCase();
            $('.' + sections).hide();
            $('.' + sectionOn).show();
        });

        $('form.crm-check').on('submit', function(e) {

            //e.preventDefault();
            /*
            var form = $(this),
                validationMessage = '',
                errorMessages = '',
                validationType = '',
                inputFields = ['input[type="text"]', 'input[type="number"]', 'input[type="checkbox"]', 'input[type="radio"]', 'select', 'textarea'],
                fieldsWithValidValue,
                fields;

            form.find('div.validation-message').remove();

            // loop each validation-group
            form.find('.validation-group:visible').each(function() {

                validationType = $(this).attr('data-validation-type');
                validationMessage = $(this).attr('data-validation-message');

                var tmp = ['required--one-or-more', 'required--one', 'required--all']
                if (tmp.indexOf(validationType) != -1) {
                    fieldsWithValidValue = $.unique($(this).removeClass('invalid').find(inputFields.join(',')).map(function () {
                        return formCheckValid(this);
                    }).get());
                }

                switch (validationType) {
                    case 'required--one-or-more':
                    case 'required--one':
                        if (fieldsWithValidValue.length == 0) {
                            $(this).addClass('invalid');
                            errorMessages += '
' + validationMessage + '
';
                        }
                        break;

                    case 'required--all':
                        fields = $.unique($(this).removeClass('invalid').find(inputFields.join(',')).map(function() {
                            return this.name;
                        }).get());

                        if (fields.length > fieldsWithValidValue.length) {
                            $(this).addClass('invalid');
                            errorMessages += '
' + validationMessage + '
';
                        }
                        break;

                    case 'required--set':

                        var fields, setOK,
                            setsOK = false,
                            sets = $(this).removeClass('invalid').attr('data-validation-set').split('|');

                        for (var s = 0, sl = sets.length; s < sl; s ++) {

                            fields = sets[s].split(',');
                            setOK = true;
                            for (var f = 0, fl = fields.length; f < fl; f ++) {
                                if (!formCheckValid($(this).find('input[name="' + fields[f] + '"]').get(0))) {
                                    setOK = false;
                                    break;
                                }
                            }
                            if (setOK) {
                                setsOK = true;
                                break;
                            }
                        }
                        if (!setsOK) {
                            $(this).addClass('invalid');
                            errorMessages += '
' + validationMessage + '
';
                        }
                        break;
                }
            });

            if (errorMessages != '') {
                form.find('input[type="submit"]').before('

' + errorMessages + '

');
                return false;
            }
            */

            /* Not ready yet
            // all the validate-groups have been checked - now check the form
            if (formValidationType = form.attr('data-form-validation-type')) {
                switch (formValidationType) {
                    case 'required--set':
                        var groups, groupOK,
                            setsOK = false,
                            sets = $(form).removeClass('invalid').attr('data-form-validation-set').split('|');

                        console.log(sets);

                        for (var s = 0, sl = sets.length; s < sl; s ++) {

                            groups = sets[s].split(',');
                            groupOK = true;
                            for (var f = 0, fl = groups.length; f < fl; f ++) {
                                if (true ) {
                                    groupOK = false;
                                    break;
                                }
                            }
                            if (groupOK) {
                                setsOK = true;
                                break;
                            }
                        }
                        if (!setsOK) {
                            form.addClass('invalid');
                            errorMessages += '
' + validationMessage + '
';
                        }
                        break;

                    break;
                }
            }
            */

            // MANUAL OVERRIDES HERE
            /*
            if (form.attr('id') == 'form__fraud-type') { // redirect to new or old website based on user input
                var redirects = ['disabilityCarers', 'abroad', 'idFraud', 'savingsCapital'];
                var selected = form.find('input[type="checkbox"][name="fraud-type"]:checked').map(function() {
                    return this.value;
                }).get();
                var redirectsSelected = [];/*$.grep(selected, function(n) {
                    return ( redirects.indexOf(n) != -1 );
                });
                if (redirectsSelected.length > 0) {
                    e.preventDefault();
                    document.location.href = 'https://secure.dwp.gov.uk/benefitfraud/';
                }

            }
             */
            return true;

        });
    });
})();

    /*

    $('form.crm-check-form').on('submit', function(e) {

        var form = $(this), errorMessage = '';

        // check (groups of) checkboxes where (at least) one must be checked
        var ids = $.unique(form.find('.fieldset').removeClass('invalid').find('input[type="checkbox"].required--one-or-more').map(function() {
            return this.name;
        }).get());
        if (ids.length > 0) {
            var idsChecked = $.unique(form.find('input[type="checkbox"].required--one-or-more:checked').map(function () {
                return (this.name);
            }).get());

            if (idsChecked.length < ids.length) { // not all groups of checkboxes have at least one checked
                // report the issue. Filter out the checked IDs
                ids = $.grep(ids, function (n) {
                    return ( idsChecked.indexOf(n) == -1 );
                });

                for (var i = 0, il = ids.length; i < il; i++) {
                    form.find('#fieldset--' + ids[i]).each(function () {
                        $(this).addClass('invalid');
                        errorMessage += '
' + $(this).attr('data-error-message') + '
';

                    });
                };
            }
        }

        // check required radio buttons

        var ids = $.unique(form.find('.fieldset').find('input[type="radio"].required').map(function() {
            return this.name.replace('helper--', '');
        }).get());
        if (ids.length > 0) {
            var idsChecked = $.unique(form.find('input[type="radio"].required:checked').map(function () {
                return this.name.replace('helper--', '');
            }).get());

            if (idsChecked.length < ids.length) { // not all required sets of radio buttons have been ticked
                // report the issue. Filter out the checked IDs
                ids = $.grep(ids, function (n) {
                    return (idsChecked.indexOf(n) == -1);
                });

                for (var i = 0, il = ids.length; i < il; i++) {
                    form.find('#fieldset--' + ids[i]).each(function() {
                        // set the invalid class and add functionality to remove it
                        $(this).addClass('invalid').attr('data-error-id', i).find('input[type="radio"]').each(function() {

                            $(this).on('click', function () {
                                var errorID = $(this).parents('.invalid').removeClass('invalid').attr('data-error-id');
                                $('#error__' + errorID).remove();
                                if (form.find('div.validation-message').find('li').length == 0) {
                                    form.find('div.validation-message').remove();
                                }
                            });
                        });
                        errorMessage += '
' + $(this).attr('data-error-message') + '
';
                    });
                };
            }
        }

        // check required text fields
        var parentNames = [];

        var ids = $.unique(form.find('.fieldset').removeClass('invalid').find('input[type="text"].required:visible, input[type="number"].required:visible').map(function() {
            return this.name.replace('helper--', '');
        }).get());
        console.log(ids);
        if (ids.length > 0) {
            var idsValid = $.unique(form.find('input[type="text"].required:visible, input[type="number"].required:visible').map(function () {
                // TODO: add validation based on regexp
                if ($(this).val() == '') {
                    parentNames.push($(this).attr('data-parent-fieldset'));
                    return null
                } else {
                    return this.name.replace('helper--', '');
                }

            }).get());
console.log(idsValid);
            if (idsValid.length < ids.length) { // not all required sets of radio buttons have been ticked
                // report the issue. Filter out the valid IDs
                ids = $.grep(ids, function (n) {
                    return (idsValid.indexOf(n) == -1);
                });

                console.log(ids);

                for (var i = 0, il = ids.length; i < il; i++) {
                    console.log('invalidating #fieldset--' + ids[i]);
                    form.find('#fieldset--' + ids[i]).each(function () {
                        $(this).addClass('invalid');
                        errorMessage += '
' + $(this).attr('data-error-message') + '
';
                    });
                };
                for (var i = 0, il = parentNames.length; i < il; i++) {
                    console.log('invalidating #fieldset--' + parentNames[i]);
                    form.find('#fieldset--' + parentNames[i]).each(function () {
                        $(this).addClass('invalid');
                        errorMessage += '
' + $(this).attr('data-error-message') + '
';
                    });
                };

            }
            console.log('------');
        }

        if (errorMessage != '') {
            form.find('div.validation-message').remove();
            form.find('input[type="submit"]').before('

' + errorMessage + '

');

            return false
        }

return false;

    });
    */
<commit_msg>Fix in Progress<commit_after>(function() {

    var formCheckValid = function(el) {
        var inputType = (el.tagName.toLowerCase() == 'textarea') ? 'textarea' : $(el).attr('type');

        switch (inputType) {
            case 'radio':
            case 'checkbox':
                return (el.checked) ? el.name : null;
                break;
            case 'text':
            case 'number':
            case 'textarea':
                var pattern = (pattern = $(el).attr('data-pattern')) ? pattern : $(el).attr('pattern');
                if (pattern != null) {
                    var result = $(el).val().match(new RegExp(pattern,"gi"));
                    return (result!= null && result.length > 0 && result[0] != '') ?el.name : null;
                } else {
                    return ($(el).val() != '') ? el.name : null;
                }
                break;
            default:
                return null;
        }
    };

    $(document).ready(function() {
        $('a.previousPage').each(function() {
            $(this).on('click', function() {
                if (!confirm('Are you sure you want to go back? You may lose form data.\n\nNB: We need to assess the need and functionality of this link')) {
                    return false;
                }
            });

        });

        /* display-none-js is a class that should only work to hide information when javascript is enabled */
        $('.display-none-js').hide();

        /* generic toggle functionality */
        $('.toggle-section').on('click', function() {
            var sections = $(this).parents('.form-group').attr('data-target');
            var sectionOn = $(this).parents('.form-group').attr('data-target') + '__' + $(this).val().toLowerCase();
            $('.' + sections).hide();
            $('.' + sectionOn).show();
        });

        $('form.crm-check').on('submit', function(e) {

            //e.preventDefault();

            var form = $(this),
                validationMessage = '',
                errorMessages = '',
                validationType = '',
                inputFields = ['input[type="text"]', 'input[type="number"]', 'input[type="checkbox"]', 'input[type="radio"]', 'select', 'textarea'],
                fieldsWithValidValue,
                fields;

            form.find('div.validation-message').remove();

            // loop each validation-group
            /*
            form.find('.validation-group:visible').each(function() {

                validationType = $(this).attr('data-validation-type');
                validationMessage = $(this).attr('data-validation-message');

                var tmp = ['required--one-or-more', 'required--one', 'required--all']
                if (tmp.indexOf(validationType) != -1) {
                    fieldsWithValidValue = $.unique($(this).removeClass('invalid').find(inputFields.join(',')).map(function () {
                        return formCheckValid(this);
                    }).get());
                }

                switch (validationType) {
                    case 'required--one-or-more':
                    case 'required--one':
                        if (fieldsWithValidValue.length == 0) {
                            $(this).addClass('invalid');
                            errorMessages += '
' + validationMessage + '
';
                        }
                        break;

                    case 'required--all':
                        fields = $.unique($(this).removeClass('invalid').find(inputFields.join(',')).map(function() {
                            return this.name;
                        }).get());

                        if (fields.length > fieldsWithValidValue.length) {
                            $(this).addClass('invalid');
                            errorMessages += '
' + validationMessage + '
';
                        }
                        break;

                    case 'required--set':

                        var fields, setOK,
                            setsOK = false,
                            sets = $(this).removeClass('invalid').attr('data-validation-set').split('|');

                        for (var s = 0, sl = sets.length; s < sl; s ++) {

                            fields = sets[s].split(',');
                            setOK = true;
                            for (var f = 0, fl = fields.length; f < fl; f ++) {
                                if (!formCheckValid($(this).find('input[name="' + fields[f] + '"]').get(0))) {
                                    setOK = false;
                                    break;
                                }
                            }
                            if (setOK) {
                                setsOK = true;
                                break;
                            }
                        }
                        if (!setsOK) {
                            $(this).addClass('invalid');
                            errorMessages += '
' + validationMessage + '
';
                        }
                        break;
                }
            });
             */
            if (errorMessages != '') {
                form.find('input[type="submit"]').before('

' + errorMessages + '

');
                return false;
            }

            /* Not ready yet
            // all the validate-groups have been checked - now check the form
            if (formValidationType = form.attr('data-form-validation-type')) {
                switch (formValidationType) {
                    case 'required--set':
                        var groups, groupOK,
                            setsOK = false,
                            sets = $(form).removeClass('invalid').attr('data-form-validation-set').split('|');

                        console.log(sets);

                        for (var s = 0, sl = sets.length; s < sl; s ++) {

                            groups = sets[s].split(',');
                            groupOK = true;
                            for (var f = 0, fl = groups.length; f < fl; f ++) {
                                if (true ) {
                                    groupOK = false;
                                    break;
                                }
                            }
                            if (groupOK) {
                                setsOK = true;
                                break;
                            }
                        }
                        if (!setsOK) {
                            form.addClass('invalid');
                            errorMessages += '
' + validationMessage + '
';
                        }
                        break;

                    break;
                }
            }
            */

            // MANUAL OVERRIDES HERE
            /*
            if (form.attr('id') == 'form__fraud-type') { // redirect to new or old website based on user input
                var redirects = ['disabilityCarers', 'abroad', 'idFraud', 'savingsCapital'];
                var selected = form.find('input[type="checkbox"][name="fraud-type"]:checked').map(function() {
                    return this.value;
                }).get();
                var redirectsSelected = [];/*$.grep(selected, function(n) {
                    return ( redirects.indexOf(n) != -1 );
                });
                if (redirectsSelected.length > 0) {
                    e.preventDefault();
                    document.location.href = 'https://secure.dwp.gov.uk/benefitfraud/';
                }

            }
             */
            return true;

        });
    });
})();

    /*

    $('form.crm-check-form').on('submit', function(e) {

        var form = $(this), errorMessage = '';

        // check (groups of) checkboxes where (at least) one must be checked
        var ids = $.unique(form.find('.fieldset').removeClass('invalid').find('input[type="checkbox"].required--one-or-more').map(function() {
            return this.name;
        }).get());
        if (ids.length > 0) {
            var idsChecked = $.unique(form.find('input[type="checkbox"].required--one-or-more:checked').map(function () {
                return (this.name);
            }).get());

            if (idsChecked.length < ids.length) { // not all groups of checkboxes have at least one checked
                // report the issue. Filter out the checked IDs
                ids = $.grep(ids, function (n) {
                    return ( idsChecked.indexOf(n) == -1 );
                });

                for (var i = 0, il = ids.length; i < il; i++) {
                    form.find('#fieldset--' + ids[i]).each(function () {
                        $(this).addClass('invalid');
                        errorMessage += '
' + $(this).attr('data-error-message') + '
';

                    });
                };
            }
        }

        // check required radio buttons

        var ids = $.unique(form.find('.fieldset').find('input[type="radio"].required').map(function() {
            return this.name.replace('helper--', '');
        }).get());
        if (ids.length > 0) {
            var idsChecked = $.unique(form.find('input[type="radio"].required:checked').map(function () {
                return this.name.replace('helper--', '');
            }).get());

            if (idsChecked.length < ids.length) { // not all required sets of radio buttons have been ticked
                // report the issue. Filter out the checked IDs
                ids = $.grep(ids, function (n) {
                    return (idsChecked.indexOf(n) == -1);
                });

                for (var i = 0, il = ids.length; i < il; i++) {
                    form.find('#fieldset--' + ids[i]).each(function() {
                        // set the invalid class and add functionality to remove it
                        $(this).addClass('invalid').attr('data-error-id', i).find('input[type="radio"]').each(function() {

                            $(this).on('click', function () {
                                var errorID = $(this).parents('.invalid').removeClass('invalid').attr('data-error-id');
                                $('#error__' + errorID).remove();
                                if (form.find('div.validation-message').find('li').length == 0) {
                                    form.find('div.validation-message').remove();
                                }
                            });
                        });
                        errorMessage += '
' + $(this).attr('data-error-message') + '
';
                    });
                };
            }
        }

        // check required text fields
        var parentNames = [];

        var ids = $.unique(form.find('.fieldset').removeClass('invalid').find('input[type="text"].required:visible, input[type="number"].required:visible').map(function() {
            return this.name.replace('helper--', '');
        }).get());
        console.log(ids);
        if (ids.length > 0) {
            var idsValid = $.unique(form.find('input[type="text"].required:visible, input[type="number"].required:visible').map(function () {
                // TODO: add validation based on regexp
                if ($(this).val() == '') {
                    parentNames.push($(this).attr('data-parent-fieldset'));
                    return null
                } else {
                    return this.name.replace('helper--', '');
                }

            }).get());
console.log(idsValid);
            if (idsValid.length < ids.length) { // not all required sets of radio buttons have been ticked
                // report the issue. Filter out the valid IDs
                ids = $.grep(ids, function (n) {
                    return (idsValid.indexOf(n) == -1);
                });

                console.log(ids);

                for (var i = 0, il = ids.length; i < il; i++) {
                    console.log('invalidating #fieldset--' + ids[i]);
                    form.find('#fieldset--' + ids[i]).each(function () {
                        $(this).addClass('invalid');
                        errorMessage += '
' + $(this).attr('data-error-message') + '
';
                    });
                };
                for (var i = 0, il = parentNames.length; i < il; i++) {
                    console.log('invalidating #fieldset--' + parentNames[i]);
                    form.find('#fieldset--' + parentNames[i]).each(function () {
                        $(this).addClass('invalid');
                        errorMessage += '
' + $(this).attr('data-error-message') + '
';
                    });
                };

            }
            console.log('------');
        }

        if (errorMessage != '') {
            form.find('div.validation-message').remove();
            form.find('input[type="submit"]').before('

' + errorMessage + '

');

            return false
        }

return false;

    });
    */
<|endoftext|>


<commit_before>/**
 * @author mrdoob / http://mrdoob.com/
 * @author bhouston / http://exocortex.com/
 */

( function ( THREE ) {

	THREE.Raycaster = function ( origin, direction, near, far ) {

		this.ray = new THREE.Ray( origin, direction );

		// normalized ray.direction required for accurate distance calculations
		if( this.ray.direction.length() > 0 ) {

			this.ray.direction.normalize();

		}

		this.near = near || 0;
		this.far = far || Infinity;

	};

	var sphere = new THREE.Sphere();
	var localRay = new THREE.Ray();
	var facePlane = new THREE.Plane();
	var intersectPoint = new THREE.Vector3();

	var inverseMatrix = new THREE.Matrix4();

	var descSort = function ( a, b ) {

		return a.distance - b.distance;

	};

	var intersectObject = function ( object, raycaster, intersects ) {

		if ( object instanceof THREE.Particle ) {

			var distance = raycaster.ray.distanceToPoint( object.matrixWorld.getPosition() );

			if ( distance > object.scale.x ) {

				return intersects;

			}

			intersects.push( {

				distance: distance,
				point: object.position,
				face: null,
				object: object

			} );

		} else if ( object instanceof THREE.Mesh ) {

			// Checking boundingSphere distance to ray
			sphere.set(
				object.matrixWorld.getPosition(),
				object.geometry.boundingSphere.radius * object.matrixWorld.getMaxScaleOnAxis() );

			if ( ! raycaster.ray.isIntersectionSphere( sphere ) ) {

				return intersects;

			}

			// Checking faces

			var geometry = object.geometry;
			var vertices = geometry.vertices;

			var isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial;
			var objectMaterials = isFaceMaterial === true ? object.material.materials : null;

			var side = object.material.side;

			var a, b, c, d;
			var precision = raycaster.precision;

			object.matrixRotationWorld.extractRotation( object.matrixWorld );

			inverseMatrix.getInverse( object.matrixWorld );

			localRay.copy( raycaster.ray ).transform( inverseMatrix );

			for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) {

				var face = geometry.faces[ f ];

				var material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : object.material;

				if ( material === undefined ) continue;

				facePlane.setFromNormalAndCoplanarPoint( face.normal, vertices[face.a] );

				var planeDistance = localRay.distanceToPlane( facePlane );

				// bail if raycaster and plane are parallel
				if ( Math.abs( planeDistance ) < precision ) continue;

				// if negative distance, then plane is behind raycaster
				if ( planeDistance < 0 ) continue;

				// check if we hit the wrong side of a single sided face
				side = material.side;
				if( side !== THREE.DoubleSide ) {

					var planeSign = localRay.direction.dot( facePlane.normal );

					if( ! ( side === THREE.FrontSide ? planeSign < 0 : planeSign > 0 ) ) continue;

				}

				// this can be done using the planeDistance from localRay because localRay wasn't normalized, but ray was
				if ( planeDistance < raycaster.near || planeDistance > raycaster.far ) continue;

				intersectPoint = localRay.at( planeDistance, intersectPoint ); // passing in intersectPoint avoids a copy

				if ( face instanceof THREE.Face3 ) {

					a = vertices[ face.a ];
					b = vertices[ face.b ];
					c = vertices[ face.c ];

					if ( ! THREE.Triangle.containsPoint( intersectPoint, a, b, c ) ) continue;

				} else if ( face instanceof THREE.Face4 ) {

					a = vertices[ face.a ];
					b = vertices[ face.b ];
					c = vertices[ face.c ];
					d = vertices[ face.d ];

					if ( ( ! THREE.Triangle.containsPoint( intersectPoint, a, b, d ) ) &&
						 ( ! THREE.Triangle.containsPoint( intersectPoint, b, c, d ) ) ) continue;

				} else {

					// This is added because if we call out of this if/else group when none of the cases
					//    match it will add a point to the intersection list erroneously.
					throw Error( "face type not supported" );

				}

				intersects.push( {

					distance: planeDistance,	// this works because the original ray was normalized, and the transformed localRay wasn't
					point: raycaster.ray.at( planeDistance ),
					face: face,
					faceIndex: f,
					object: object

				} );

			}

		}

	};

	var intersectDescendants = function ( object, raycaster, intersects ) {

		var descendants = object.getDescendants();

		for ( var i = 0, l = descendants.length; i < l; i ++ ) {

			intersectObject( descendants[ i ], raycaster, intersects );

		}
	};

	//

	THREE.Raycaster.prototype.precision = 0.0001;

	THREE.Raycaster.prototype.set = function ( origin, direction ) {

		this.ray.set( origin, direction );

		// normalized ray.direction required for accurate distance calculations
		if( this.ray.direction.length() > 0 ) {

			this.ray.direction.normalize();

		}

	};

	THREE.Raycaster.prototype.intersectObject = function ( object, recursive ) {

		var intersects = [];

		if ( recursive === true ) {

			intersectDescendants( object, this, intersects );

		}

		intersectObject( object, this, intersects );

		intersects.sort( descSort );

		return intersects;

	};

	THREE.Raycaster.prototype.intersectObjects = function ( objects, recursive ) {

		var intersects = [];

		for ( var i = 0, l = objects.length; i < l; i ++ ) {

			intersectObject( objects[ i ], this, intersects );

			if ( recursive === true ) {

				intersectDescendants( objects[ i ], this, intersects );

			}
		}

		intersects.sort( descSort );

		return intersects;

	};

}( THREE ) );
<commit_msg>Update src/core/Raycaster.js<commit_after>/**
 * @author mrdoob / http://mrdoob.com/
 * @author bhouston / http://exocortex.com/
 */

( function ( THREE ) {

	THREE.Raycaster = function ( origin, direction, near, far ) {

		this.ray = new THREE.Ray( origin, direction );

		// normalized ray.direction required for accurate distance calculations
		if( this.ray.direction.lengthSq() > 0 ) {

			this.ray.direction.normalize();

		}

		this.near = near || 0;
		this.far = far || Infinity;

	};

	var sphere = new THREE.Sphere();
	var localRay = new THREE.Ray();
	var facePlane = new THREE.Plane();
	var intersectPoint = new THREE.Vector3();

	var inverseMatrix = new THREE.Matrix4();

	var descSort = function ( a, b ) {

		return a.distance - b.distance;

	};

	var intersectObject = function ( object, raycaster, intersects ) {

		if ( object instanceof THREE.Particle ) {

			var distance = raycaster.ray.distanceToPoint( object.matrixWorld.getPosition() );

			if ( distance > object.scale.x ) {

				return intersects;

			}

			intersects.push( {

				distance: distance,
				point: object.position,
				face: null,
				object: object

			} );

		} else if ( object instanceof THREE.Mesh ) {

			// Checking boundingSphere distance to ray
			sphere.set(
				object.matrixWorld.getPosition(),
				object.geometry.boundingSphere.radius * object.matrixWorld.getMaxScaleOnAxis() );

			if ( ! raycaster.ray.isIntersectionSphere( sphere ) ) {

				return intersects;

			}

			// Checking faces

			var geometry = object.geometry;
			var vertices = geometry.vertices;

			var isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial;
			var objectMaterials = isFaceMaterial === true ? object.material.materials : null;

			var side = object.material.side;

			var a, b, c, d;
			var precision = raycaster.precision;

			object.matrixRotationWorld.extractRotation( object.matrixWorld );

			inverseMatrix.getInverse( object.matrixWorld );

			localRay.copy( raycaster.ray ).transform( inverseMatrix );

			for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) {

				var face = geometry.faces[ f ];

				var material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : object.material;

				if ( material === undefined ) continue;

				facePlane.setFromNormalAndCoplanarPoint( face.normal, vertices[face.a] );

				var planeDistance = localRay.distanceToPlane( facePlane );

				// bail if raycaster and plane are parallel
				if ( Math.abs( planeDistance ) < precision ) continue;

				// if negative distance, then plane is behind raycaster
				if ( planeDistance < 0 ) continue;

				// check if we hit the wrong side of a single sided face
				side = material.side;
				if( side !== THREE.DoubleSide ) {

					var planeSign = localRay.direction.dot( facePlane.normal );

					if( ! ( side === THREE.FrontSide ? planeSign < 0 : planeSign > 0 ) ) continue;

				}

				// this can be done using the planeDistance from localRay because localRay wasn't normalized, but ray was
				if ( planeDistance < raycaster.near || planeDistance > raycaster.far ) continue;

				intersectPoint = localRay.at( planeDistance, intersectPoint ); // passing in intersectPoint avoids a copy

				if ( face instanceof THREE.Face3 ) {

					a = vertices[ face.a ];
					b = vertices[ face.b ];
					c = vertices[ face.c ];

					if ( ! THREE.Triangle.containsPoint( intersectPoint, a, b, c ) ) continue;

				} else if ( face instanceof THREE.Face4 ) {

					a = vertices[ face.a ];
					b = vertices[ face.b ];
					c = vertices[ face.c ];
					d = vertices[ face.d ];

					if ( ( ! THREE.Triangle.containsPoint( intersectPoint, a, b, d ) ) &&
						 ( ! THREE.Triangle.containsPoint( intersectPoint, b, c, d ) ) ) continue;

				} else {

					// This is added because if we call out of this if/else group when none of the cases
					//    match it will add a point to the intersection list erroneously.
					throw Error( "face type not supported" );

				}

				intersects.push( {

					distance: planeDistance,	// this works because the original ray was normalized, and the transformed localRay wasn't
					point: raycaster.ray.at( planeDistance ),
					face: face,
					faceIndex: f,
					object: object

				} );

			}

		}

	};

	var intersectDescendants = function ( object, raycaster, intersects ) {

		var descendants = object.getDescendants();

		for ( var i = 0, l = descendants.length; i < l; i ++ ) {

			intersectObject( descendants[ i ], raycaster, intersects );

		}
	};

	//

	THREE.Raycaster.prototype.precision = 0.0001;

	THREE.Raycaster.prototype.set = function ( origin, direction ) {

		this.ray.set( origin, direction );

		// normalized ray.direction required for accurate distance calculations
		if( this.ray.direction.length() > 0 ) {

			this.ray.direction.normalize();

		}

	};

	THREE.Raycaster.prototype.intersectObject = function ( object, recursive ) {

		var intersects = [];

		if ( recursive === true ) {

			intersectDescendants( object, this, intersects );

		}

		intersectObject( object, this, intersects );

		intersects.sort( descSort );

		return intersects;

	};

	THREE.Raycaster.prototype.intersectObjects = function ( objects, recursive ) {

		var intersects = [];

		for ( var i = 0, l = objects.length; i < l; i ++ ) {

			intersectObject( objects[ i ], this, intersects );

			if ( recursive === true ) {

				intersectDescendants( objects[ i ], this, intersects );

			}
		}

		intersects.sort( descSort );

		return intersects;

	};

}( THREE ) );
<|endoftext|>


<commit_before>//= require jquery_ujs
//= require jquery.easing.1.3
//= require jquery-ui-1.9.2.custom.min
//= require wax.g.min
//= require cartodb-gmapsv3
//= require cartodb-infowindow-min
//= require protected-infowindow-min
//= require imgLiquid.min
//= require jstorage.min
//= require lodash.min
//= require backbone-min
//= require class
//= require backbone.cartodb
//= require d3.v2.min
//= require geojson
//= require jquery.tipsy
//= require jquery.fileupload
//= require jquery.fileupload-ui
//= require jquery.fileupload-fp
//= require gfw
//= require_tree .

// Map needs to be a global var or
// CapybaraHelpers#draw_polygon won't work

var
loaded           = false,
map              = null,
previousState    = null,
globalZindex     = 300,
subscribeMap;

GOD               = {},
legend            = {},
analysis          = {},
Timeline          = {},
wall              = {},
sourceWindow      = {},
gallery           = {},
languageSelector  = {},
layerSelector     = {},
Infowindow        = {};

function loadOtherStuff(callback) {

  if ($("body.home.index").length > 0) {
    wall = new gfw.ui.view.Wall();
    $("body").append(wall.render());
  }

  sourceWindow  = new gfw.ui.view.SourceWindow();
  Infowindow    = new CartoDBInfowindow(map, { className: "story_infowindow", width: 215 });

  $("body").append(sourceWindow.render());

  $(".styled.checkbox").on("click", function(e) {
    e.preventDefault();
    e.stopPropagation();

    $(this).toggleClass("checked");
    $(this).hasClass("checked") ? $(this).find("input").val(1) : $(this).find("input").val(0);

  });

  gallery           = new gfw.ui.view.Gallery({ title: "Other WRI sites" });
  languageSelector  = new gfw.ui.view.LanguageSelector();

  $("body").append(languageSelector.render());

  $(".more_stories li").on("mouseleave", function(e) {
    var $this = $(this);
    $this.find(".infowindow").fadeOut(50);
  });

  $(".more_stories li").on("mouseenter", function(e) {
    var $this = $(this);
    $this.find(".infowindow").fadeIn(50);
  });

  gallery.addHandler("#other_sites_ribbon");

  languageSelector.addLanguage({ code: "en",    lang: "en", title: "English" });
  languageSelector.addLanguage({ code: "fr",    lang: "fr", title: "French" });
  languageSelector.addLanguage({ code: "es",    lang: "es", title: "Spanish" });
  languageSelector.addLanguage({ code: "pt",    lang: "pt", title: "Portuguese" });
  languageSelector.addLanguage({ code: "id",    lang: "id", title: "Indonesian" });
  languageSelector.addLanguage({ code: "zh-CN", lang: "cn", title: "Chinese" });
  languageSelector.addLanguage({ code: "ru",    lang: "ru", title: "Russian" });
  languageSelector.addLanguage({ code: "ar",    lang: "ar", title: "Arabic" });

  languageSelector.addHandler(".lang_selector a");

  $(".lang_selector a").on("click", function(e) {
    e.preventDefault();
    e.stopPropagation();

    languageSelector.toggleHidden();
    GOD.add(languageSelector, languageSelector.hide);
  });

  Timeline = new gfw.ui.view.Timeline({
    container: $("#map")
  });

  window.timeline = Timeline;

  Circle.init();
  Filter.init();

  $(".scroll").jScrollPane();

  callback && callback();

}

function loadGFW(callback) {

  if (loaded) {

    callback && callback();
    return;
  }

  loaded = true;

  GOD = new gfw.ui.view.GOD();
  window.GOD = GOD;

  map = new google.maps.Map(document.getElementById("map"), config.mapOptions);

  var styledMap = new google.maps.StyledMapType(config.BASE_MAP_STYLE, { name: "terrain_style" });

  map.mapTypes.set("terrain_style", styledMap);
  map.setMapTypeId("terrain_style");

  google.maps.event.addDomListener(map, 'click', function (ev) {
    ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;
    Infowindow.close();
  });

  google.maps.event.addListener(map, 'maptypeid_changed', function() {
    if (map.getMapTypeId() == 'Tree Height') $("#credit-control").html(config.mapStyles.TREEHEIGHT.alt).fadeIn(250);
    else $("#credit-control").html("").fadeOut(250);
  });

  var creditNode = document.createElement('div');
  creditNode.id = 'credit-control';
  map.controls[google.maps.ControlPosition.BOTTOM_RIGHT].push(creditNode);

  google.maps.event.addListenerOnce(map, 'idle', function (ev) {

    GFW(function(env) {

      GFW.app = new env.app.Instance(map, {
        user       : 'wri-01',
        layerTable : 'layerinfo_minus_imazon', // TODO: change back to layerinfo when we have imazon
        logging    : false
      });

      GFW.app.run();
      GFW.env = env;

      loadOtherStuff(callback);

    });

  });

  // Layer selector
  layerSelector = new gfw.ui.view.LayerSelector({ map: map });
  $("#map").append(layerSelector.render());
  layerSelector.setDraggable(true);

  // Legend
  legend = new gfw.ui.view.Legend();
  $("#map").append(legend.render());
  legend.setDraggable(true);

  // Analysis
  analysis = new gfw.ui.view.Analysis({ map: map });
  $("#map").append(analysis.render());
  analysis.info.setDraggable(true);

}

(function(window,undefined){

  if ($("body.countries").hasClass("index")) CountryMenu.drawCountries();

  $("nav .home.ajax").on("click", function(e) {
    e.preventDefault();
    e.stopPropagation();
    window.router.navigate("", { trigger: true });
    $(".backdrop").fadeOut(250);

  });

  $("nav .countries.ajax").on("click", function(e) {
    e.preventDefault();
    e.stopPropagation();
    window.router.navigate("countries", { trigger: true });
  });

  $(".share_link").off("click");
  $(".share_link").on("click", function(e) {
    e.preventDefault();
    $(".backdrop").fadeIn(250, function() {

      var top = ( $(window).height() - $("#share").height() ) / 2+$(window).scrollTop() + "px",
      left = ( $(window).width() - $("#share").width() ) / 2+$(window).scrollLeft() + "px";

      $("#share").css({top: top, left:left});
      $("#share").fadeIn(250);
    });
  });

  $(".analysis").off("click");

  $(".analysis").on("click", function(e) {
    e.preventDefault();
    console.log('a');

    $("body").animate({ scrollTop: 0 }, 250, function() {
      analysis.startAnalyzing();
    });

  });

  $(".close_icon").on("click", function(e) {
    e.preventDefault();
    $(".backdrop").fadeOut(250);

    $("#share, #subscribe, #other_wri_sites").fadeOut(250);

  });

  $("#subscribe .map").on("click", function(e) {
    SubscriptionMap.clearMapErrors();
  });

  $("#subscribe .input-field").on("click", function(e) {
    SubscriptionMap.clearEmailErrors();
  });

  $("#share, #subscribe, #other_wri_sites").on("click", function(e) {
    e.stopPropagation();
  });

  $(".wri.selector").on("click", function(e) {
    e.preventDefault();
    e.stopPropagation();

    $("#other_wri_sites").fadeIn(250);
  });

  $(".subscribe").on("click", function(e) {
    e.preventDefault();
    e.stopPropagation();
    SubscriptionMap.show();
  });

  $('#subscribe .remove').on("click", function(e){
    e.preventDefault();
    e.stopPropagation();
    SubscriptionMap.remove();
  });

  $('#subscribe .btn').on("click", function(e){
    e.preventDefault();
    e.stopPropagation();
    SubscriptionMap.submit();
  });

  $("nav .map.ajax").on("click", function(e) {
    e.preventDefault();
    e.stopPropagation();

    var lat = map.getCenter().lat().toFixed(GFW.app._precision);
    var lng = map.getCenter().lng().toFixed(GFW.app._precision);

    var zoom   = config.mapOptions.zoom;
    var layers = config.mapOptions.layers;

    if(layers) {
      hash = "map/" + zoom + "/" + lat + "/" + lng + "/" + config.iso + "/" + layers;
      window.router.navigate(hash, { trigger: true, replace: true });
    } else {
      hash = "map/" + zoom + "/" + lat + "/" + lng + "/" + config.iso;
      window.router.navigate(hash, { trigger: true });
    }

    $(".backdrop").fadeOut(250);

  });

  return false;

})(window);

$(function(){

  var resizePID;

  var Router = Backbone.Router.extend({

    routes: {
      "map":                              "map",
      "map/":                             "map",
      "map/:zoom/:lat/:lon":              "mapWithCoordinates",
      "map/:zoom/:lat/:lon/:iso":         "mapWithCoordinates",
      "map/:zoom/:lat/:lon/:iso/*layers": "mapWithCoordinates",
      "/":                                "home",
      "":                                 "home"
    },

    home: function(query, page) {
      loadGFW( function() {
        Navigation.showState("home");
      });
    },

    map: function() {
      if ($.browser.msie) $(document).scrollTop(0);

      loadGFW( function() {
        Navigation.showState("map");
      });

    },

    mapWithCoordinates: function(zoom, lat, lon, iso, layers) {
      if (lat && lon) { config.mapOptions.center = new google.maps.LatLng(lat, lon); }
      if (zoom)       { config.mapOptions.zoom   = parseInt(zoom, 10); }
      if (layers)     { config.mapOptions.layers = layers; }

      if (!iso) config.iso = "ALL";
      else config.iso = iso;

      loadGFW( function() {
        Navigation.showState("map");
      });

      if (lat && lon) map.setCenter(new google.maps.LatLng(lat, lon));
      if (iso != "ALL") analysis._loadCountry(iso);
    }

  });

  if ($("body.about").length > 0 || $("body.sources").length > 0 || $("body.blog").length > 0 || $("body.countries").length > 0 || $("body.stories").length > 0) {
    loadOtherStuff();
  }

  window.router = new Router;

  $("#layer a.title").on("click", function(e) {
    e.preventDefault();
    e.stopPropagation();
  });

  $("#filters ul.filters li a").on("click", function(e) {
    e.preventDefault();
    e.stopPropagation();
  });

  if ($("body.home.index").length > 0) {
    Backbone.history.start({ pushState: true });
  }

  if ($("body.stories.show .carrousel").length > 0) {
    carrousel = new gfw.ui.view.Carrousel();
  }

  function hideOvers() {

    if ($("#share:visible").length > 0) {
      $("#share").fadeOut(250);
      $(".backdrop").fadeOut(250);
    }

    if ($("#subscribe:visible").length > 0) {
      $("#subscribe").fadeOut(250);
      $(".backdrop").fadeOut(250);
    }

    if ($("#other_wri_sites:visible").length > 0) {
      $("#other_wri_sites").fadeOut(250);
    }

  }

  $(".backdrop").on("click", function(e) {
    hideOvers();
  });

  $(document).on("click", function(e) {
    hideOvers();
  });

  $(document).keyup(function(e) {
    if (e.keyCode == 27) {
      hideOvers();
    } // esc
  });

  $(window).resize(function() {
    clearTimeout(resizePID);
    resizePID = setTimeout(function() { resizeWindow(); }, 100);
  });

  function resizeWindow(e) {
    if (showMap) {
      if (GFW.app) GFW.app.open();
      Filter.calcFiltersPosition();
    }
  }

  if ($("div[data-load]:visible").length > 0) {
    addCircle("forest", "bars", { legendUnit: "m", countryCode: countryCode, width: 300, title: "Height", subtitle:"Tree height distribution", legend:"with {{n}} tall trees", hoverColor: "#333333", color: "#333333", unit: "km2" });
    addCircle("forma", "lines", { countryCode: countryCode, width: 300, title: "FORMA", subtitle:"Forest clearing alerts", legend:"In the last month", hoverColor: "#A1BA42", color: "#A1BA42" });
  }

});
<commit_msg>Removed wall<commit_after>//= require jquery_ujs
//= require jquery.easing.1.3
//= require jquery-ui-1.9.2.custom.min
//= require wax.g.min
//= require cartodb-gmapsv3
//= require cartodb-infowindow-min
//= require protected-infowindow-min
//= require imgLiquid.min
//= require jstorage.min
//= require lodash.min
//= require backbone-min
//= require class
//= require backbone.cartodb
//= require d3.v2.min
//= require geojson
//= require jquery.tipsy
//= require jquery.fileupload
//= require jquery.fileupload-ui
//= require jquery.fileupload-fp
//= require gfw
//= require_tree .

// Map needs to be a global var or
// CapybaraHelpers#draw_polygon won't work

var
loaded           = false,
map              = null,
previousState    = null,
globalZindex     = 300,
subscribeMap;

GOD               = {},
legend            = {},
analysis          = {},
Timeline          = {},
wall              = {},
sourceWindow      = {},
gallery           = {},
languageSelector  = {},
layerSelector     = {},
Infowindow        = {};

function loadOtherStuff(callback) {

  //if ($("body.home.index").length > 0) {
    //wall = new gfw.ui.view.Wall();
    //$("body").append(wall.render());
  //}

  sourceWindow  = new gfw.ui.view.SourceWindow();
  Infowindow    = new CartoDBInfowindow(map, { className: "story_infowindow", width: 215 });

  $("body").append(sourceWindow.render());

  $(".styled.checkbox").on("click", function(e) {
    e.preventDefault();
    e.stopPropagation();

    $(this).toggleClass("checked");
    $(this).hasClass("checked") ? $(this).find("input").val(1) : $(this).find("input").val(0);

  });

  gallery           = new gfw.ui.view.Gallery({ title: "Other WRI sites" });
  languageSelector  = new gfw.ui.view.LanguageSelector();

  $("body").append(languageSelector.render());

  $(".more_stories li").on("mouseleave", function(e) {
    var $this = $(this);
    $this.find(".infowindow").fadeOut(50);
  });

  $(".more_stories li").on("mouseenter", function(e) {
    var $this = $(this);
    $this.find(".infowindow").fadeIn(50);
  });

  gallery.addHandler("#other_sites_ribbon");

  languageSelector.addLanguage({ code: "en",    lang: "en", title: "English" });
  languageSelector.addLanguage({ code: "fr",    lang: "fr", title: "French" });
  languageSelector.addLanguage({ code: "es",    lang: "es", title: "Spanish" });
  languageSelector.addLanguage({ code: "pt",    lang: "pt", title: "Portuguese" });
  languageSelector.addLanguage({ code: "id",    lang: "id", title: "Indonesian" });
  languageSelector.addLanguage({ code: "zh-CN", lang: "cn", title: "Chinese" });
  languageSelector.addLanguage({ code: "ru",    lang: "ru", title: "Russian" });
  languageSelector.addLanguage({ code: "ar",    lang: "ar", title: "Arabic" });

  languageSelector.addHandler(".lang_selector a");

  $(".lang_selector a").on("click", function(e) {
    e.preventDefault();
    e.stopPropagation();

    languageSelector.toggleHidden();
    GOD.add(languageSelector, languageSelector.hide);
  });

  Timeline = new gfw.ui.view.Timeline({
    container: $("#map")
  });

  window.timeline = Timeline;

  Circle.init();
  Filter.init();

  $(".scroll").jScrollPane();

  callback && callback();

}

function loadGFW(callback) {

  if (loaded) {

    callback && callback();
    return;
  }

  loaded = true;

  GOD = new gfw.ui.view.GOD();
  window.GOD = GOD;

  map = new google.maps.Map(document.getElementById("map"), config.mapOptions);

  var styledMap = new google.maps.StyledMapType(config.BASE_MAP_STYLE, { name: "terrain_style" });

  map.mapTypes.set("terrain_style", styledMap);
  map.setMapTypeId("terrain_style");

  google.maps.event.addDomListener(map, 'click', function (ev) {
    ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;
    Infowindow.close();
  });

  google.maps.event.addListener(map, 'maptypeid_changed', function() {
    if (map.getMapTypeId() == 'Tree Height') $("#credit-control").html(config.mapStyles.TREEHEIGHT.alt).fadeIn(250);
    else $("#credit-control").html("").fadeOut(250);
  });

  var creditNode = document.createElement('div');
  creditNode.id = 'credit-control';
  map.controls[google.maps.ControlPosition.BOTTOM_RIGHT].push(creditNode);

  google.maps.event.addListenerOnce(map, 'idle', function (ev) {

    GFW(function(env) {

      GFW.app = new env.app.Instance(map, {
        user       : 'wri-01',
        layerTable : 'layerinfo_minus_imazon', // TODO: change back to layerinfo when we have imazon
        logging    : false
      });

      GFW.app.run();
      GFW.env = env;

      loadOtherStuff(callback);

    });

  });

  // Layer selector
  layerSelector = new gfw.ui.view.LayerSelector({ map: map });
  $("#map").append(layerSelector.render());
  layerSelector.setDraggable(true);

  // Legend
  legend = new gfw.ui.view.Legend();
  $("#map").append(legend.render());
  legend.setDraggable(true);

  // Analysis
  analysis = new gfw.ui.view.Analysis({ map: map });
  $("#map").append(analysis.render());
  analysis.info.setDraggable(true);

}

(function(window,undefined){

  if ($("body.countries").hasClass("index")) CountryMenu.drawCountries();

  $("nav .home.ajax").on("click", function(e) {
    e.preventDefault();
    e.stopPropagation();
    window.router.navigate("", { trigger: true });
    $(".backdrop").fadeOut(250);

  });

  $("nav .countries.ajax").on("click", function(e) {
    e.preventDefault();
    e.stopPropagation();
    window.router.navigate("countries", { trigger: true });
  });

  $(".share_link").off("click");
  $(".share_link").on("click", function(e) {
    e.preventDefault();
    $(".backdrop").fadeIn(250, function() {

      var top = ( $(window).height() - $("#share").height() ) / 2+$(window).scrollTop() + "px",
      left = ( $(window).width() - $("#share").width() ) / 2+$(window).scrollLeft() + "px";

      $("#share").css({top: top, left:left});
      $("#share").fadeIn(250);
    });
  });

  $(".analysis").off("click");

  $(".analysis").on("click", function(e) {
    e.preventDefault();
    console.log('a');

    $("body").animate({ scrollTop: 0 }, 250, function() {
      analysis.startAnalyzing();
    });

  });

  $(".close_icon").on("click", function(e) {
    e.preventDefault();
    $(".backdrop").fadeOut(250);

    $("#share, #subscribe, #other_wri_sites").fadeOut(250);

  });

  $("#subscribe .map").on("click", function(e) {
    SubscriptionMap.clearMapErrors();
  });

  $("#subscribe .input-field").on("click", function(e) {
    SubscriptionMap.clearEmailErrors();
  });

  $("#share, #subscribe, #other_wri_sites").on("click", function(e) {
    e.stopPropagation();
  });

  $(".wri.selector").on("click", function(e) {
    e.preventDefault();
    e.stopPropagation();

    $("#other_wri_sites").fadeIn(250);
  });

  $(".subscribe").on("click", function(e) {
    e.preventDefault();
    e.stopPropagation();
    SubscriptionMap.show();
  });

  $('#subscribe .remove').on("click", function(e){
    e.preventDefault();
    e.stopPropagation();
    SubscriptionMap.remove();
  });

  $('#subscribe .btn').on("click", function(e){
    e.preventDefault();
    e.stopPropagation();
    SubscriptionMap.submit();
  });

  $("nav .map.ajax").on("click", function(e) {
    e.preventDefault();
    e.stopPropagation();

    var lat = map.getCenter().lat().toFixed(GFW.app._precision);
    var lng = map.getCenter().lng().toFixed(GFW.app._precision);

    var zoom   = config.mapOptions.zoom;
    var layers = config.mapOptions.layers;

    if(layers) {
      hash = "map/" + zoom + "/" + lat + "/" + lng + "/" + config.iso + "/" + layers;
      window.router.navigate(hash, { trigger: true, replace: true });
    } else {
      hash = "map/" + zoom + "/" + lat + "/" + lng + "/" + config.iso;
      window.router.navigate(hash, { trigger: true });
    }

    $(".backdrop").fadeOut(250);

  });

  return false;

})(window);

$(function(){

  var resizePID;

  var Router = Backbone.Router.extend({

    routes: {
      "map":                              "map",
      "map/":                             "map",
      "map/:zoom/:lat/:lon":              "mapWithCoordinates",
      "map/:zoom/:lat/:lon/:iso":         "mapWithCoordinates",
      "map/:zoom/:lat/:lon/:iso/*layers": "mapWithCoordinates",
      "/":                                "home",
      "":                                 "home"
    },

    home: function(query, page) {
      loadGFW( function() {
        Navigation.showState("home");
      });
    },

    map: function() {
      if ($.browser.msie) $(document).scrollTop(0);

      loadGFW( function() {
        Navigation.showState("map");
      });

    },

    mapWithCoordinates: function(zoom, lat, lon, iso, layers) {
      if (lat && lon) { config.mapOptions.center = new google.maps.LatLng(lat, lon); }
      if (zoom)       { config.mapOptions.zoom   = parseInt(zoom, 10); }
      if (layers)     { config.mapOptions.layers = layers; }

      if (!iso) config.iso = "ALL";
      else config.iso = iso;

      loadGFW( function() {
        Navigation.showState("map");
      });

      if (lat && lon) map.setCenter(new google.maps.LatLng(lat, lon));
      if (iso != "ALL") analysis._loadCountry(iso);
    }

  });

  if ($("body.about").length > 0 || $("body.sources").length > 0 || $("body.blog").length > 0 || $("body.countries").length > 0 || $("body.stories").length > 0) {
    loadOtherStuff();
  }

  window.router = new Router;

  $("#layer a.title").on("click", function(e) {
    e.preventDefault();
    e.stopPropagation();
  });

  $("#filters ul.filters li a").on("click", function(e) {
    e.preventDefault();
    e.stopPropagation();
  });

  if ($("body.home.index").length > 0) {
    Backbone.history.start({ pushState: true });
  }

  if ($("body.stories.show .carrousel").length > 0) {
    carrousel = new gfw.ui.view.Carrousel();
  }

  function hideOvers() {

    if ($("#share:visible").length > 0) {
      $("#share").fadeOut(250);
      $(".backdrop").fadeOut(250);
    }

    if ($("#subscribe:visible").length > 0) {
      $("#subscribe").fadeOut(250);
      $(".backdrop").fadeOut(250);
    }

    if ($("#other_wri_sites:visible").length > 0) {
      $("#other_wri_sites").fadeOut(250);
    }

  }

  $(".backdrop").on("click", function(e) {
    hideOvers();
  });

  $(document).on("click", function(e) {
    hideOvers();
  });

  $(document).keyup(function(e) {
    if (e.keyCode == 27) {
      hideOvers();
    } // esc
  });

  $(window).resize(function() {
    clearTimeout(resizePID);
    resizePID = setTimeout(function() { resizeWindow(); }, 100);
  });

  function resizeWindow(e) {
    if (showMap) {
      if (GFW.app) GFW.app.open();
      Filter.calcFiltersPosition();
    }
  }

  if ($("div[data-load]:visible").length > 0) {
    addCircle("forest", "bars", { legendUnit: "m", countryCode: countryCode, width: 300, title: "Height", subtitle:"Tree height distribution", legend:"with {{n}} tall trees", hoverColor: "#333333", color: "#333333", unit: "km2" });
    addCircle("forma", "lines", { countryCode: countryCode, width: 300, title: "FORMA", subtitle:"Forest clearing alerts", legend:"In the last month", hoverColor: "#A1BA42", color: "#A1BA42" });
  }

});
<|endoftext|>


<commit_before>// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.

//= require jquery
//= require jquery_ujs
//= require foundation

//= require_tree .
$(document).ready(function() {

  $('body').on('click', '#home', function(event) {
    event.preventDefault()

    var myUrl = $(this).attr('href')
    $.ajax({type: 'get', url: myUrl})
      .done(function(response) {
        $('.container').remove()
        $('header').remove()

        // var r = $.parseHTML(response)
        var $header = $(response).filter('header')
        var $container = $(response).filter('.container')
        console.log($header)
        $('body').append($header)
        $('body').append($container)
        init()

      })
  })

  $('body').on('click', '#user', function(event) {
    event.preventDefault()

    var myUrl = $(this).attr('href')
    $.ajax({type: 'get', url: myUrl})
      .done(function(response) {
        $('.container').remove()
        $('header').remove()
        var $header = $(response).filter('header')
        var $container = $(response).filter('.container')

        $('body').append($header)
        $('body').append($container)
      })
  })

  $('body').on('click', '#new-playlist', function(event) {
  event.preventDefault()
  var myUrl = $(this).attr('href')

  $.ajax({type: 'get', url: myUrl})
    .done(function(response) {
      // $('header').remove()
      $('.container').remove()

      $('body').append($('<div>').addClass('container row').append(response))

    })

  })

  $('body').on('submit', '#new_playlist', function(event) {
    event.preventDefault()
    var myUrl = $(this).attr('action')
    $.ajax({type: 'post', url: myUrl, data: $(this).serialize()})
      .done(function(response) {
        $('.container').remove()
        $('body').append($('<div>').addClass('container row').append(response))
      })
  })

  $('body').on('click', '#new-song', function(event) {
    event.preventDefault()
    var myUrl = $(this).attr('href')
    $.ajax({type: 'get', url: myUrl})
      .done(function(response) {
        $('.container').remove()
        $('body').append($('<div>').addClass('container row').append(response))
      })

  })

  $('body').on('submit', '#search-songs', function(event) {
    event.preventDefault()

     var myUrl = $(this).attr('action')
    $.ajax({type: 'get', url: myUrl, data: $(this).serialize()})
      .done(function(response) {
        $('.container').remove()
        $('body').append($('<div>').addClass('container row').append(response))
      })
  })

  $('body').on('click', '.add-song', function(event) {
    event.preventDefault()

     var myUrl = $(this).parent().attr('action').replace(/\?(.+)/, '')
     var params = $(this).parent().attr('action').match(/\?(.+)/)[1]
    $.ajax({type: 'post', beforeSend: function(xhr) {xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))}, url: myUrl, data: params})
      .done(function(response) {
        $('.container').remove()

        var $container = $(response).filter('.container')
        var $newSong = $(response).find('.coverart').last().find('a')
        $('body').append($container)

        init()
      })
  })

  var minUpdateUserDistance = 0.01 //km
  var userId = $("div[style='display:none']").attr('id')
  var firebaseRef = new Firebase("https://blinding-fire-43.firebaseio.com/");
  var geo_options = {
  enableHighAccuracy: true,
  };

  var currentdate = new Date();

  // Create a GeoFire index
  var geoFire = new GeoFire(firebaseRef);

  function getLocation() {
      if (navigator.geolocation) {
          navigator.geolocation.watchPosition(checkGeoFire, null, geo_options);
      } else {
          x.innerHTML = "Geolocation is not supported by this browser.";
      }
  }

  function checkGeoFire(position) {
    $.ajax({type: 'patch', url: '/users/'+userId+'', data: { user: {latitude: position.coords.latitude, longitude: position.coords.longitude}}})
    }

getLocation()

  var audio;
  var playlist;
  var tracks;
  var current;

init();
function init(){
    current = 0;
    audio = $('#audio');
    playlist = $('#playlist');
    tracks = playlist.find('.coverart a').clone();
    $('#secret-playlist').find('a').remove()
    $div = $('footer').find('#secret-playlist')
    $('#secret-playlist').append(tracks)
    len = tracks.length;
    audio[0].volume = .50;
    audio[0].play();
    playlist.find('a').click(function(e){
        e.preventDefault();
        link = $(this);
        current = link.parent().index();
        run(link, audio[0]);
    });
    audio[0].addEventListener('ended',function(e){
        current++;
        if(current == len){
            current = 0;
            console.log('done')
            link = $div.find('a')[0];
        }else{
            link = $div.find('a')[current];
        }
        console.log($(link))
        run($(link),audio[0]);
    });
}
function run(link, player){
        console.log(link)
        player.src = link.attr('href');
        par = link.parent();
        par.addClass('active').siblings().removeClass('active');
        audio[0].load();
        audio[0].play();
}

})

$(function(){ $(document).foundation(); });
<commit_msg>added ajax to find playlists view<commit_after>// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.

//= require jquery
//= require jquery_ujs
//= require foundation

//= require_tree .
$(document).ready(function() {

  $('body').on('click', '#home', function(event) {
    event.preventDefault()

    var myUrl = $(this).attr('href')
    $.ajax({type: 'get', url: myUrl})
      .done(function(response) {
        $('.container').remove()
        $('header').remove()

        // var r = $.parseHTML(response)
        var $header = $(response).filter('header')
        var $container = $(response).filter('.container')
        console.log($header)
        $('body').append($header)
        $('body').append($container)
        init()

      })
  })

  $('body').on('click', '#user', function(event) {
    event.preventDefault()

    var myUrl = $(this).attr('href')
    $.ajax({type: 'get', url: myUrl})
      .done(function(response) {
        $('.container').remove()
        $('header').remove()
        var $header = $(response).filter('header')
        var $container = $(response).filter('.container')

        $('body').append($header)
        $('body').append($container)
      })
  })

  $('body').on('click', '#new-playlist', function(event) {
  event.preventDefault()
  var myUrl = $(this).attr('href')

  $.ajax({type: 'get', url: myUrl})
    .done(function(response) {
      // $('header').remove()
      $('.container').remove()

      $('body').append($('<div>').addClass('container row').append(response))

    })

  })

  $('body').on('submit', '#new_playlist', function(event) {
    event.preventDefault()
    var myUrl = $(this).attr('action')
    $.ajax({type: 'post', url: myUrl, data: $(this).serialize()})
      .done(function(response) {
        $('.container').remove()
        $('body').append($('<div>').addClass('container row').append(response))
      })
  })

  $('body').on('click', '#new-song', function(event) {
    event.preventDefault()
    var myUrl = $(this).attr('href')
    $.ajax({type: 'get', url: myUrl})
      .done(function(response) {
        $('.container').remove()
        $('body').append($('<div>').addClass('container row').append(response))
      })

  })

  $('body').on('submit', '#search-songs', function(event) {
    event.preventDefault()

     var myUrl = $(this).attr('action')
    $.ajax({type: 'get', url: myUrl, data: $(this).serialize()})
      .done(function(response) {
        $('.container').remove()
        $('body').append($('<div>').addClass('container row').append(response))
      })
  })

  $('body').on('click', '.add-song', function(event) {
    event.preventDefault()

     var myUrl = $(this).parent().attr('action').replace(/\?(.+)/, '')
     var params = $(this).parent().attr('action').match(/\?(.+)/)[1]
    $.ajax({type: 'post', beforeSend: function(xhr) {xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))}, url: myUrl, data: params})
      .done(function(response) {
        $('.container').remove()

        var $container = $(response).filter('.container')
        var $newSong = $(response).find('.coverart').last().find('a')
        $('body').append($container)

        init()
      })
  })

  $('body').on('click', '#find-playlist', function(event) {
    event.preventDefault()

    var myUrl = $(this).attr('href')
    $.ajax({type: 'get', url: myUrl})
      .done(function(response) {
        $('.container').remove()
        $('header').remove()
        var $header = $(response).filter('header')
        var $container = $(response).filter('.container')
        $('body').append($header)
        $('body').append($container)
      })
  })

  var minUpdateUserDistance = 0.01 //km
  var userId = $("div[style='display:none']").attr('id')
  var firebaseRef = new Firebase("https://blinding-fire-43.firebaseio.com/");
  var geo_options = {
  enableHighAccuracy: true,
  };

  var currentdate = new Date();

  // Create a GeoFire index
  var geoFire = new GeoFire(firebaseRef);

  function getLocation() {
      if (navigator.geolocation) {
          navigator.geolocation.watchPosition(checkGeoFire, null, geo_options);
      } else {
          x.innerHTML = "Geolocation is not supported by this browser.";
      }
  }

  function checkGeoFire(position) {
    $.ajax({type: 'patch', url: '/users/'+userId+'', data: { user: {latitude: position.coords.latitude, longitude: position.coords.longitude}}})
    }

getLocation()

  var audio;
  var playlist;
  var tracks;
  var current;

init();
function init(){
    current = 0;
    audio = $('#audio');
    playlist = $('#playlist');
    tracks = playlist.find('.coverart a').clone();
    $('#secret-playlist').find('a').remove()
    $div = $('footer').find('#secret-playlist')
    $('#secret-playlist').append(tracks)
    len = tracks.length;
    audio[0].volume = .50;
    audio[0].play();
    playlist.find('a').click(function(e){
        e.preventDefault();
        link = $(this);
        current = link.parent().index();
        run(link, audio[0]);
    });
    audio[0].addEventListener('ended',function(e){
        current++;
        if(current == len){
            current = 0;
            console.log('done')
            link = $div.find('a')[0];
        }else{
            link = $div.find('a')[current];
        }
        console.log($(link))
        run($(link),audio[0]);
    });
}
function run(link, player){
        console.log(link)
        player.src = link.attr('href');
        par = link.parent();
        par.addClass('active').siblings().removeClass('active');
        audio[0].load();
        audio[0].play();
}

})

$(function(){ $(document).foundation(); });
<|endoftext|>


<commit_before>//= require lodash
//= require jquery
//= require angular
//= require jquery
//= require angular-ui-router
//= require angular-animate
//= require angular-resource
//= require angular-sanitize
//= require angular-bootstrap
//= require angular-gravatar
//= require angular-loading-bar
//= require ng-currency
//= require angucomplete-alt
//= require angular-cookies
//= require angular-progress-arc/angular-progress-arc
//= require angular-smart-table
//= require angular-ui-select
//= require microplugin
//= require selectize
//= require bootstrap
//= require bootstrap-sass
//= require moment.js
//= require bootstrap3-datetimepicker
//= require objectpath
//= require angular-schema-form
//= require tv4
//= require_tree .
//= require d3
//= require nvd3
//= require angular-nvd3
//= require ngDraggable
//= require angular-filter
<commit_msg>added resource to application.js<commit_after>//= require lodash
//= require jquery
//= require angular
//= require jquery
//= require angular-ui-router
//= require angular-animate
//= require angular-resource
//= require angular-sanitize
//= require angular-bootstrap
//= require angular-gravatar
//= require angular-loading-bar
//= require ng-currency
//= require angucomplete-alt
//= require angular-cookies
//= require angular-progress-arc/angular-progress-arc
//= require angular-smart-table
//= require angular-ui-select
//= require microplugin
//= require selectize
//= require bootstrap
//= require bootstrap-sass
//= require moment.js
//= require bootstrap3-datetimepicker
//= require objectpath
//= require angular-schema-form
//= require tv4
//= require_tree .
//= require d3
//= require nvd3
//= require angular-nvd3
//= require ngDraggable
//= require angular-filter
//= require es5-shim
<|endoftext|>