<commit_before>var DAY_SUFFIXES = { 1: "st", 2: "nd", 3: "rd" };
var DATATABLES_COLUMNS = { PROTO: 0, DST_PORT: 1, DST_IP: 2, SRC_IP: 3, FIRST_SEEN: 4, LAST_SEEN: 5, COUNT: 6 }
var IP_COUNTRY = {};
var POINT_SIZE = 4.5;

jQuery.extend(jQuery.fn.dataTableExt.oSort, {
    // Reference: http://cdn.datatables.net/plug-ins/3cfcc339e89/sorting/date-euro.js
    "date-custom-pre": function ( a ) {
        var x = Infinity;
        var match = a.match(/time=["']([^"']+)/);
        if (match !== null) {
            var frDatea = match[1].split(' ');
            var frTimea = frDatea[1].split('.')[0].split(':');
            var frDatea2 = frDatea[0].split('-');

            x = (frDatea2[0] + frDatea2[1] + frDatea2[2] + frTimea[0] + frTimea[1] + frTimea[2]) * 1;
        }
        return x;
    },
    "date-custom-asc": function ( a, b ) {
        return a - b;
    },
    "date-custom-desc": function ( a, b ) {
        return b - a;
    }
});

jQuery.extend(jQuery.fn.dataTableExt.oSort, {
    "port-custom-pre": function ( a ) {
        var x = 0;
        var match = a.match(/(\d+).*/);
        if (match !== null) {
            x = match[1] * 1;
        }
        return x;
    },
    "port-custom-asc": function ( a, b ) {
        return a - b;
    },
    "port-custom-desc": function ( a, b ) {
        return b - a;
    }
});

// Reference: http://en.wikipedia.org/wiki/Private_network
function isLocalAddress(ip) {
    if (ip.startsWith("10.") || ip.startsWith("192.168.") || ip.startsWith("127."))
        return true;
    else if (ip.startsWith("172.")) {
        var _ = parseInt(ip.split(".")[1]);
        return ((_ >= 16) && (_ <= 31))
    }
    else
        return false;
};

google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);

function drawChart() {
    var data = google.visualization.arrayToDataTable([
//<!TRENDLINE_DATA!>
]);

    var options = {
        title: '',
        hAxis: {title: 'Date', format: 'yyyy-MM-dd', textStyle: {fontSize: 12}, titleTextStyle: {italic: false, fontSize: 13}},
        vAxis: {title: 'Intruders', textStyle: {fontSize: 12}, titleTextStyle: {italic: false, fontSize: 13}, logScale: true, minValue: 0},
        trendlines: { },
        legend: {position: 'right', textStyle: {fontSize: 13}},
        fontName: 'monospace',
        chartArea: {left: 70, top: 20, width: "75%", height: "80%"},
    };

    for (var i = 0; i < data.getNumberOfColumns() - 1; i++)
        options.trendlines[i] = {type: 'polynomial', degree: 3, opacity: 0.5, lineWidth: 2, tooltip: false};

    var chart = new google.visualization.ScatterChart(document.getElementById('chart'));

    chart.draw(data, options);

    google.visualization.events.addListener(chart, 'onmouseover', function(e){
        var circles = $('svg g g g circle');
        if (circles.length) {
            var fill = circles[circles.length - 1].attributes["fill"].value;
            $("circle[fill='" + fill + "']").attr("r", POINT_SIZE * 1.3);
            $("circle[fill!='" + fill + "']").attr("fill-opacity", 0.05);
            $("path[stroke!='" + fill + "']").attr("stroke-opacity", 0.05);
        }
    });

    google.visualization.events.addListener(chart, 'onmouseout', function(e){
        $("circle").attr("r", POINT_SIZE);
        $("circle").attr("fill-opacity", 1);
        $("path").attr("stroke-opacity", 0.5);
    });

}

var dataset = [
//<!DATASET!>
];

$(document).ready(function() {
    $('#details').DataTable( {
        data: dataset,
        columns: [
            { title: "proto" },
            { title: "dst_port", type: "port-custom" },
            { title: "dst_ip" },
            { title: "src_ip" },
            { title: "first_seen", type: "date-custom" },
            { title: "last_seen", type: "date-custom" },
            { title: "count" },
        ],
        columnDefs: [
            {
                orderSequence: [ "desc", "asc" ],
                targets: [ DATATABLES_COLUMNS.FIRST_SEEN, DATATABLES_COLUMNS.LAST_SEEN, DATATABLES_COLUMNS.COUNT ]
            },
            {
                render: function (data, type, row) {
                    var parts = data.split(' ');
                    var day = parts[0].split('-')[2];
                    var dayint = parseInt(day);
                    var suffix = (dayint > 10 && dayint < 20) ? "th" : DAY_SUFFIXES[dayint % 10] || "th";
                    return "
" + day + "" + suffix + " " + parts[1].split('.')[0] + "
";
                },
                targets: [ DATATABLES_COLUMNS.FIRST_SEEN, DATATABLES_COLUMNS.LAST_SEEN ],
            },
        ],
        iDisplayLength: 25,
        aaSorting: [ [DATATABLES_COLUMNS.LAST_SEEN, 'desc'] ],
        fnRowCallback: function(nRow, aData, iDisplayIndex, iDisplayIndexFull) {
            function nslookup(event, ui) {
                var elem = $(this);
                var html = elem.parent().html();
                var match = html.match(/\d+\.\d+\.\d+\.\d+/);

                if (match !== null) {
                    var ip = match[0];
                    $.ajax("https://stat.ripe.net/data/whois/data.json?resource=" + ip, { dataType:"jsonp", ip: ip })
                    .success(function(json) {
                        // Reference: http://bugs.jqueryui.com/ticket/8740#comment:21
                        var found = null;
                        var msg = "";

                        for (var i = json.data.records.length - 1; i >= 0 ; i--) {
                            if ((json.data.records[i][0].key.toLowerCase().indexOf("inetnum") != -1) || (json.data.records[i][0].key.toLowerCase().indexOf("netrange") != -1)){
                                found = i;
                                break;
                            }
                        }

                        if (found !== null) {
                            for (var j = 0; j < json.data.records[found].length; j++) {
                                msg += json.data.records[found][j].key + ": " + json.data.records[found][j].value;
                                msg += "
";
                            }
                            msg = msg.replace(/(\-\+)+/g, "--").replace(/(\-\+)+/g, "--");
                        }

                        $.ajax("https://stat.ripe.net/data/dns-chain/data.json?resource=" + ip, { dataType:"jsonp", ip: ip, msg: msg})
                        .success(function(json) {
                            var _ = json.data.reverse_nodes[this.ip];
                            if ((_.length === 0)||(_ === "localhost")) {
                                /*var parts = this.ip.split('.');
                                _ = "";
                                for (var i = parts.length - 1; i >= 0; i--)
                                    _ += parts[i] + ".";
                                _ += "in-addr.arpa";*/
                                _ = "-";
                            }
                            var msg = "
" + _ + "
" + this.msg;
                            ui.tooltip.find(".ui-tooltip-content").html(msg);
                        });
                    });
                }
            }

            $('[title]', nRow).tooltip();

            $.each([DATATABLES_COLUMNS.SRC_IP, DATATABLES_COLUMNS.DST_IP], function(index, value) {
                var cell = $('td:eq(' + value + ')', nRow);

                if (cell === null)
                    return false;

                var html = cell.html();

                if (html === null)
                    return false;

                if ((html.indexOf('flag') > -1) || (html.indexOf('lan') > -1) || (html.indexOf(',') > -1))
                    return false;

                var match = html.match(/\d+\.\d+\.\d+\.\d+/);
                if (match === null)
                    return false;

                var interval = null;
                var img = "";
                var ip = match[0];
                var options = { content: "please wait...", open: nslookup, position: { my: "left center", at: "right+10 top-50" } };

                if (!isLocalAddress(ip)) {
                    if (!(ip in IP_COUNTRY)) {
                        IP_COUNTRY[ip] = null;
                        $.ajax("https://stat.ripe.net/data/geoloc/data.json?resource=" + ip, { dataType:"jsonp", ip: ip, cell: cell })
                        .success(function(json) {
                            var span_ip = $("").html(this.ip + " ");

                            if ((json.data.locations.length > 0) && (json.data.locations[0].country !== "ANO")) {
                                IP_COUNTRY[this.ip] = json.data.locations[0].country.toLowerCase().split('-')[0];
                                img = '';  // title="' + IP_COUNTRY[this.ip].toUpperCase() + '"
                                span_ip.tooltip(options);
                            }
                            else {
                                IP_COUNTRY[this.ip] = "unknown";
                                img = '';
                            }

                            this.cell.html("").append(span_ip).append($(img).tooltip());
                        });
                    }
                    else if (IP_COUNTRY[ip] !== null) {
                        img = ' '

                        var span_ip = $("").html(ip + " ");
                        span_ip.tooltip(options);

                        cell.html("").append(span_ip).append($(img).tooltip());
                    }
                    else {
                        interval = setInterval(function(ip, cell){
                            html = cell.html();
                            if ((IP_COUNTRY[ip] !== null) && (html.indexOf("flag-") === -1)) {
                                img = ' '

                                var span_ip = $("").html(ip + " ");
                                span_ip.tooltip(options);

                                cell.html("").append(span_ip).append($(img).tooltip());
                                clearInterval(interval);
                            }
                        }, 1000, ip, cell);
                    }
                }
                else {
                    img = '';
                    cell.html(html + " ").append($(img).tooltip());
                }
            });
        },

    } );
} );
<commit_msg>Minor style improvements<commit_after>var DAY_SUFFIXES = { 1: "st", 2: "nd", 3: "rd" };
var DATATABLES_COLUMNS = { PROTO: 0, DST_PORT: 1, DST_IP: 2, SRC_IP: 3, FIRST_SEEN: 4, LAST_SEEN: 5, COUNT: 6 }
var IP_COUNTRY = {};
var POINT_SIZE = 4.5;
var LINE_WIDTH = 1.5;
var DEFAULT_OPACITY = 0.4;

jQuery.extend(jQuery.fn.dataTableExt.oSort, {
    // Reference: http://cdn.datatables.net/plug-ins/3cfcc339e89/sorting/date-euro.js
    "date-custom-pre": function ( a ) {
        var x = Infinity;
        var match = a.match(/time=["']([^"']+)/);
        if (match !== null) {
            var frDatea = match[1].split(' ');
            var frTimea = frDatea[1].split('.')[0].split(':');
            var frDatea2 = frDatea[0].split('-');

            x = (frDatea2[0] + frDatea2[1] + frDatea2[2] + frTimea[0] + frTimea[1] + frTimea[2]) * 1;
        }
        return x;
    },
    "date-custom-asc": function ( a, b ) {
        return a - b;
    },
    "date-custom-desc": function ( a, b ) {
        return b - a;
    }
});

jQuery.extend(jQuery.fn.dataTableExt.oSort, {
    "port-custom-pre": function ( a ) {
        var x = 0;
        var match = a.match(/(\d+).*/);
        if (match !== null) {
            x = match[1] * 1;
        }
        return x;
    },
    "port-custom-asc": function ( a, b ) {
        return a - b;
    },
    "port-custom-desc": function ( a, b ) {
        return b - a;
    }
});

// Reference: http://en.wikipedia.org/wiki/Private_network
function isLocalAddress(ip) {
    if (ip.startsWith("10.") || ip.startsWith("192.168.") || ip.startsWith("127."))
        return true;
    else if (ip.startsWith("172.")) {
        var _ = parseInt(ip.split(".")[1]);
        return ((_ >= 16) && (_ <= 31))
    }
    else
        return false;
};

google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);

function drawChart() {
    var data = google.visualization.arrayToDataTable([
//<!TRENDLINE_DATA!>
]);

    var options = {
        title: '',
        hAxis: {title: 'Date', format: 'yyyy-MM-dd', textStyle: {fontSize: 12}, titleTextStyle: {italic: false, fontSize: 13}},
        vAxis: {title: 'Intruders', textStyle: {fontSize: 12}, titleTextStyle: {italic: false, fontSize: 13}, logScale: true, minValue: 0},
        trendlines: { },
        legend: {position: 'right', textStyle: {fontSize: 13}},
        fontName: 'monospace',
        chartArea: {left: 70, top: 20, width: "75%", height: "80%"},
    };

    for (var i = 0; i < data.getNumberOfColumns() - 1; i++)
        options.trendlines[i] = {type: 'polynomial', degree: 3, opacity: 1, lineWidth: 1, tooltip: false};

    var chart = new google.visualization.ScatterChart(document.getElementById('chart'));

    chart.draw(data, options);

    google.visualization.events.addListener(chart, 'onmouseover', function(e){
        var circles = $('svg g g g circle');
        if (circles.length) {
            var fill = circles[circles.length - 1].attributes["fill"].value;
            $("circle[fill='" + fill + "']").attr("r", POINT_SIZE * 1.3);
            $("circle[fill='" + fill + "']").attr("fill-opacity", 1);
            $("path[stroke='" + fill + "']").attr("stroke-opacity", 1);
            $("path[stroke='" + fill + "']").attr("stroke-width", LINE_WIDTH * 3);
        }
    });

    google.visualization.events.addListener(chart, 'onmouseout', function(e){
        $("circle").attr("r", POINT_SIZE).attr("fill-opacity", DEFAULT_OPACITY);
        $("path").attr("stroke-width", LINE_WIDTH).attr("stroke-opacity", DEFAULT_OPACITY);
    });

    google.visualization.events.addListener(chart, 'ready', function(e){
        google.visualization.events.trigger(chart, 'onmouseout', e);
    });
}

var dataset = [
//<!DATASET!>
];

$(document).ready(function() {
    $('#details').DataTable( {
        data: dataset,
        columns: [
            { title: "proto" },
            { title: "dst_port", type: "port-custom" },
            { title: "dst_ip" },
            { title: "src_ip" },
            { title: "first_seen", type: "date-custom" },
            { title: "last_seen", type: "date-custom" },
            { title: "count" },
        ],
        columnDefs: [
            {
                orderSequence: [ "desc", "asc" ],
                targets: [ DATATABLES_COLUMNS.FIRST_SEEN, DATATABLES_COLUMNS.LAST_SEEN, DATATABLES_COLUMNS.COUNT ]
            },
            {
                render: function (data, type, row) {
                    var parts = data.split(' ');
                    var day = parts[0].split('-')[2];
                    var dayint = parseInt(day);
                    var suffix = (dayint > 10 && dayint < 20) ? "th" : DAY_SUFFIXES[dayint % 10] || "th";
                    return "
" + day + "" + suffix + " " + parts[1].split('.')[0] + "
";
                },
                targets: [ DATATABLES_COLUMNS.FIRST_SEEN, DATATABLES_COLUMNS.LAST_SEEN ],
            },
        ],
        iDisplayLength: 25,
        aaSorting: [ [DATATABLES_COLUMNS.LAST_SEEN, 'desc'] ],
        fnRowCallback: function(nRow, aData, iDisplayIndex, iDisplayIndexFull) {
            function nslookup(event, ui) {
                var elem = $(this);
                var html = elem.parent().html();
                var match = html.match(/\d+\.\d+\.\d+\.\d+/);

                if (match !== null) {
                    var ip = match[0];
                    $.ajax("https://stat.ripe.net/data/whois/data.json?resource=" + ip, { dataType:"jsonp", ip: ip })
                    .success(function(json) {
                        // Reference: http://bugs.jqueryui.com/ticket/8740#comment:21
                        var found = null;
                        var msg = "";

                        for (var i = json.data.records.length - 1; i >= 0 ; i--) {
                            if ((json.data.records[i][0].key.toLowerCase().indexOf("inetnum") != -1) || (json.data.records[i][0].key.toLowerCase().indexOf("netrange") != -1)){
                                found = i;
                                break;
                            }
                        }

                        if (found !== null) {
                            for (var j = 0; j < json.data.records[found].length; j++) {
                                msg += json.data.records[found][j].key + ": " + json.data.records[found][j].value;
                                msg += "
";
                            }
                            msg = msg.replace(/(\-\+)+/g, "--").replace(/(\-\+)+/g, "--");
                        }

                        $.ajax("https://stat.ripe.net/data/dns-chain/data.json?resource=" + ip, { dataType:"jsonp", ip: ip, msg: msg})
                        .success(function(json) {
                            var _ = json.data.reverse_nodes[this.ip];
                            if ((_.length === 0)||(_ === "localhost")) {
                                /*var parts = this.ip.split('.');
                                _ = "";
                                for (var i = parts.length - 1; i >= 0; i--)
                                    _ += parts[i] + ".";
                                _ += "in-addr.arpa";*/
                                _ = "-";
                            }
                            var msg = "
" + _ + "
" + this.msg;
                            ui.tooltip.find(".ui-tooltip-content").html(msg);
                        });
                    });
                }
            }

            $('[title]', nRow).tooltip();

            $.each([DATATABLES_COLUMNS.SRC_IP, DATATABLES_COLUMNS.DST_IP], function(index, value) {
                var cell = $('td:eq(' + value + ')', nRow);

                if (cell === null)
                    return false;

                var html = cell.html();

                if (html === null)
                    return false;

                if ((html.indexOf('flag') > -1) || (html.indexOf('lan') > -1) || (html.indexOf(',') > -1))
                    return false;

                var match = html.match(/\d+\.\d+\.\d+\.\d+/);
                if (match === null)
                    return false;

                var interval = null;
                var img = "";
                var ip = match[0];
                var options = { content: "please wait...", open: nslookup, position: { my: "left center", at: "right+10 top-50" } };

                if (!isLocalAddress(ip)) {
                    if (!(ip in IP_COUNTRY)) {
                        IP_COUNTRY[ip] = null;
                        $.ajax("https://stat.ripe.net/data/geoloc/data.json?resource=" + ip, { dataType:"jsonp", ip: ip, cell: cell })
                        .success(function(json) {
                            var span_ip = $("").html(this.ip + " ");

                            if ((json.data.locations.length > 0) && (json.data.locations[0].country !== "ANO")) {
                                IP_COUNTRY[this.ip] = json.data.locations[0].country.toLowerCase().split('-')[0];
                                img = '';  // title="' + IP_COUNTRY[this.ip].toUpperCase() + '"
                                span_ip.tooltip(options);
                            }
                            else {
                                IP_COUNTRY[this.ip] = "unknown";
                                img = '';
                            }

                            this.cell.html("").append(span_ip).append($(img).tooltip());
                        });
                    }
                    else if (IP_COUNTRY[ip] !== null) {
                        img = ' '

                        var span_ip = $("").html(ip + " ");
                        span_ip.tooltip(options);

                        cell.html("").append(span_ip).append($(img).tooltip());
                    }
                    else {
                        interval = setInterval(function(ip, cell){
                            html = cell.html();
                            if ((IP_COUNTRY[ip] !== null) && (html.indexOf("flag-") === -1)) {
                                img = ' '

                                var span_ip = $("").html(ip + " ");
                                span_ip.tooltip(options);

                                cell.html("").append(span_ip).append($(img).tooltip());
                                clearInterval(interval);
                            }
                        }, 1000, ip, cell);
                    }
                }
                else {
                    img = '';
                    cell.html(html + " ").append($(img).tooltip());
                }
            });
        },

    } );
} );
<|endoftext|>


<commit_before>// Script to synchronize a calendar to a spreadsheet and vice versa.
//
// See https://github.com/Davepar/gcalendarsync for instructions on setting this up.
//

// Set this value to match your calendar!!!
// Calendar ID can be found in the "Calendar Address" section of the Calendar Settings.
var calendarId = '<your-calendar-id>@group.calendar.google.com';
//Configure the year range you want to syncrhonize, e.g.: [2006, 2017]
var years = [];

var dateFormat = 'M/d/yyyy H:mm';

var titleRowMap = {
  'title': 'Title',
  'description': 'Description',
  'location': 'Location',
  'starttime': 'Start Time',
  'endtime': 'End Time',
  'guests': 'Guests',
  'id': 'Id'
};
var titleRowKeys = ['title', 'description', 'location', 'starttime', 'endtime', 'guests', 'id'];
var requiredFields = ['id', 'title', 'starttime', 'endtime'];

// This controls whether email invites are sent to guests when the event is created in the
// calendar. Note that any changes to the event will cause email invites to be resent.
var SEND_EMAIL_INVITES = false;

// Adds the custom menu to the active spreadsheet.
function onOpen() {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var menuEntries = [
    {
      name: "Update from Calendar",
      functionName: "syncFromCalendar"
    }, {
      name: "Update to Calendar",
      functionName: "syncToCalendar"
    }
  ];
  spreadsheet.addMenu('Calendar Sync', menuEntries);
}

// Creates a mapping array between spreadsheet column and event field name
function createIdxMap(row) {
  var idxMap = [];
  for (var idx = 0; idx < row.length; idx++) {
    var fieldFromHdr = row[idx];
    for (var titleKey in titleRowMap) {
      if (titleRowMap[titleKey] == fieldFromHdr) {
        idxMap.push(titleKey);
        break;
      }
    }
    if (idxMap.length <= idx) {
      // Header field not in map, so add null
      idxMap.push(null);
    }
  }
  return idxMap;
}

// Converts a spreadsheet row into an object containing event-related fields
function reformatEvent(row, idxMap) {
  return row.reduce(function(event, value, idx) {
    if (idxMap[idx] != null) {
      event[idxMap[idx]] = value;
    }
    return event;
  }, {});
}

// Converts a calendar event to a psuedo-sheet event.
function convertCalEvent(calEvent) {
  convertedEvent = {
    'id': calEvent.getId(),
    'title': calEvent.getTitle(),
    'description': calEvent.getDescription(),
    'location': calEvent.getLocation(),
    'guests': calEvent.getGuestList().map(function(x) {return x.getEmail();}).join(',')
  };
  if (calEvent.isAllDayEvent()) {
    convertedEvent.starttime = calEvent.getAllDayStartDate();
    var endtime = calEvent.getAllDayEndDate();
    if (endtime - convertedEvent.starttime === 24 * 3600 * 1000) {
      convertedEvent.endtime = '';
    } else {
      convertedEvent.endtime = endtime;
      if (endtime.getHours() === 0 && endtime.getMinutes() == 0) {
        convertedEvent.endtime.setSeconds(endtime.getSeconds() - 1);
      }
    }
  } else {
    convertedEvent.starttime = calEvent.getStartTime();
    convertedEvent.endtime = calEvent.getEndTime();
  }
  return convertedEvent;
}

// Converts calendar event into spreadsheet data row
function calEventToSheet(calEvent, idxMap, dataRow) {
  convertedEvent = convertCalEvent(calEvent);

  for (var idx = 0; idx < idxMap.length; idx++) {
    if (idxMap[idx] !== null) {
      dataRow[idx] = convertedEvent[idxMap[idx]];
    }
  }
}

// Returns empty string or time in milliseconds for Date object
function getEndTime(ev) {
  return ev.endtime === '' ? '' : ev.endtime.getTime();
}

// Tests whether calendar event matches spreadsheet event
function eventMatches(cev, sev) {
  var convertedCalEvent = convertCalEvent(cev);
  return convertedCalEvent.title == sev.title &&
    convertedCalEvent.description == sev.description &&
    convertedCalEvent.location == sev.location &&
    convertedCalEvent.starttime.toString() == sev.starttime.toString() &&
    getEndTime(convertedCalEvent) === getEndTime(sev) &&
    convertedCalEvent.guests == sev.guests;
}

// Determine whether required fields are missing
function fieldsMissing(idxMap) {
  return requiredFields.some(function(val) {
    return idxMap.indexOf(val) < 0;
  });
}

// Set up formats and hide ID column for empty spreadsheet
function setUpSheet(sheet, fieldKeys) {
  sheet.getRange(1, fieldKeys.indexOf('starttime') + 1, 999).setNumberFormat(dateFormat);
  sheet.getRange(1, fieldKeys.indexOf('endtime') + 1, 999).setNumberFormat(dateFormat);
  sheet.hideColumns(fieldKeys.indexOf('id') + 1);
}

// Display error alert
function errorAlert(msg, evt, ridx) {
  var ui = SpreadsheetApp.getUi();
  if (evt) {
    ui.alert('Skipping row: ' + msg + ' in event "' + evt.title + '", row ' + (ridx + 1));
  } else {
    ui.alert(msg);
  }
}

function updateEvent(calEvent, sheetEvent){
  sheetEvent.sendInvites = SEND_EMAIL_INVITES;
  if (sheetEvent.endtime === '') {
    calEvent.setAllDayDate(sheetEvent.starttime);
  } else {
    calEvent.setTime(sheetEvent.starttime, sheetEvent.endtime);
  }
  calEvent.setTitle(sheetEvent.title);
  calEvent.setDescription(sheetEvent.description);
  calEvent.setLocation(sheetEvent.location);
  var guestCal = calEvent.getGuestList().map(function (x) {
    return {
      email: x.getEmail(),
      added: false
    };
  });
  var guests = sheetEvent.guests.split(',').map(function (x) {
    return x ? x.trim() : '';
  });
  //check guests that are already invited
  for (var gIx = 0; gIx < guestCal.length; gIx++) {
    var index = guests.indexOf(guestCal[gIx].email);
    if (index >= 0) {
      guestCal[gIx].added = true;
      guests.splice(index, 1);
    }
  }
  guests.forEach(function (x) {
    if (x) calEvent.addGuest(x);
  });
  guestCal.forEach(function (x) {
    if (!x.added) {
      calEvent.removeGuest(x.email);
    }
  });
}

// Synchronize from calendar to spreadsheet.
function syncFromCalendar() {
  // Get calendar and events
  var calendar = CalendarApp.getCalendarById(calendarId);
  var calEvents = calendar.getEvents(new Date('1/1/' + (config.years ? config.years[0] : '1970')), new Date('31/12/' + (config.years ? config.years[config.years.length - 1] : '2030')));

  // Get spreadsheet and data
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getActiveSheet();
  var range = sheet.getDataRange();
  var data = range.getValues();
  var eventFound = new Array(data.length);

  // Check if spreadsheet is empty and add a title row
  var titleRow = [];
  for (var idx = 0; idx < titleRowKeys.length; idx++) {
    titleRow.push(titleRowMap[titleRowKeys[idx]]);
  }
  if (data.length < 1) {
    data.push(titleRow);
    range = sheet.getRange(1, 1, data.length, data[0].length);
    range.setValues(data);
    setUpSheet(sheet, titleRowKeys);
  }

  if (data.length == 1 && data[0].length == 1 && data[0][0] === '') {
    data[0] = titleRow;
    range = sheet.getRange(1, 1, data.length, data[0].length);
    range.setValues(data);
    setUpSheet(sheet, titleRowKeys);
  }

  // Map spreadsheet headers to indices
  var idxMap = createIdxMap(data[0]);
  var idIdx = idxMap.indexOf('id');

  // Verify header has all required fields
  if (fieldsMissing(idxMap)) {
    var reqFieldNames = requiredFields.map(function(x) {return titleRowMap[x];}).join(', ');
    errorAlert('Spreadsheet must have ' + reqFieldNames + ' columns');
    return;
  }

  // Array of IDs in the spreadsheet
  var sheetEventIds = data.slice(1).map(function(row) {return row[idIdx];});

  // Loop through calendar events
  for (var cidx = 0; cidx < calEvents.length; cidx++) {
    var calEvent = calEvents[cidx];
    var calEventId = calEvent.getId();

    var ridx = sheetEventIds.indexOf(calEventId) + 1;
    if (ridx < 1) {
      // Event not found, create it
      ridx = data.length;
      var newRow = [];
      var rowSize = idxMap.length;
      while (rowSize--) newRow.push('');
      data.push(newRow);
    } else {
      eventFound[ridx] = true;
    }
    // Update event in spreadsheet data
    calEventToSheet(calEvent, idxMap, data[ridx]);
  }

  // Remove any data rows not found in the calendar
  var rowsDeleted = 0;
  for (var idx = eventFound.length - 1; idx > 0; idx--) {
    //event doesn't exists and has an event id
    if (!eventFound[idx] && sheetEventIds[idx - 1]) {
      data.splice(idx, 1);
      rowsDeleted++;
    }
  }

  // Save spreadsheet changes
  range = sheet.getRange(1, 1, data.length, data[0].length);
  range.setValues(data);
  if (rowsDeleted > 0) {
    sheet.deleteRows(data.length + 1, rowsDeleted);
  }
}

// Synchronize from spreadsheet to calendar.
function syncToCalendar() {
  // Get calendar and events
  var calendar = CalendarApp.getCalendarById(calendarId);
  if (!calendar) {
    errorAlert('Cannot find calendar. Check instructions for set up.');
  }
  var calEvents = calendar.getEvents(new Date('1/1/' + (config.years ? config.years[0] : '1970')), new Date('31/12/' + (config.years ? config.years[config.years.length - 1] : '2030')));
  var calEventIds = calEvents.map(function(val) {return val.getId()});

  // Get spreadsheet and data
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getActiveSheet();
  var range = sheet.getDataRange();
  var data = range.getValues();
  if (data.length < 2) {
    errorAlert('Spreadsheet must have a title row and at least one data row');
    return;
  }

  // Map headers to indices
  var idxMap = createIdxMap(data[0]);
  var idIdx = idxMap.indexOf('id');
  var idRange = range.offset(0, idIdx, data.length, 1);
  var idData = idRange.getValues()

  // Verify header has all required fields
  if (fieldsMissing(idxMap)) {
    var reqFieldNames = requiredFields.map(function(x) {return titleRowMap[x];}).join(', ');
    errorAlert('Spreadsheet must have ' + reqFieldNames + ' columns');
    return;
  }

  // Loop through spreadsheet rows
  var numAdds = 0;
  var numUpdated = 0;
  var changesMade = false;
  for (var ridx = 1; ridx < data.length; ridx++) {
    var sheetEvent = reformatEvent(data[ridx], idxMap);

    // Do some error checking first
    if (!sheetEvent.title) {
      errorAlert('must have title', sheetEvent, ridx);
      continue;
    }
    if (!(sheetEvent.starttime instanceof Date)) {
      errorAlert('start time must be a date/time', sheetEvent, ridx);
      continue;
    }
    if (sheetEvent.endtime !== '') {
      if (!(sheetEvent.endtime instanceof Date)) {
        errorAlert('end time must be empty or a date/time', sheetEvent, ridx);
        continue;
      }
      if (sheetEvent.endtime < sheetEvent.starttime) {
        errorAlert('end time must be after start time for event', sheetEvent, ridx);
        continue;
      }
    }

    // Determine if spreadsheet event is already in calendar and matches
    var addEvent = true;
    if (sheetEvent.id) {
      var eventIdx = calEventIds.indexOf(sheetEvent.id);
      if (eventIdx >= 0) {
        calEventIds[eventIdx] = null;  // Prevents removing event below
        var calEvent = calEvents[eventIdx];
        if (!eventMatches(calEvent, sheetEvent)) {
          //update the event
          updateEvent(calEvent, sheetEvent);
      }
    }
    if (addEvent) {
      var newEvent;
      sheetEvent.sendInvites = SEND_EMAIL_INVITES;
      if (sheetEvent.endtime === '') {
        newEvent = calendar.createAllDayEvent(sheetEvent.title, sheetEvent.starttime, sheetEvent);
      } else {
        newEvent = calendar.createEvent(sheetEvent.title, sheetEvent.starttime, sheetEvent.endtime, sheetEvent);
      }
      // Put event ID back into spreadsheet
      idData[ridx][0] = newEvent.getId();
      changesMade = true;

      // Updating too many calendar events in a short time interval triggers an error. Still experimenting with
      // the exact values to use here, but this works for updating about 40 events.
      numAdds++;
      if (numAdds > 10) {
        Utilities.sleep(75);
      }
    }
  }

  // Save spreadsheet changes
  if (changesMade) {
    idRange.setValues(idData);
  }

  // Remove any calendar events not found in the spreadsheet
  var numToRemove = calEventIds.reduce(function(prevVal, curVal) {
    if (curVal !== null) {
      prevVal++;
    }
    return prevVal;
  }, 0);
  if (numToRemove > 0) {
    var ui = SpreadsheetApp.getUi();
    var response = ui.Button.YES;
    if (numToRemove > numUpdated) {
      response = ui.alert('Delete ' + numToRemove + ' calendar event(s) not found in spreadsheet?',
          ui.ButtonSet.YES_NO);
    }
    if (response == ui.Button.YES) {
      calEventIds.forEach(function(id, idx) {
        if (id != null) {
          calEvents[idx].deleteEvent();
          Utilities.sleep(20);
        }
      });
    }
  }
}
<commit_msg>Fix: years config was not working<commit_after>// Script to synchronize a calendar to a spreadsheet and vice versa.
//
// See https://github.com/Davepar/gcalendarsync for instructions on setting this up.
//

// Set this value to match your calendar!!!
// Calendar ID can be found in the "Calendar Address" section of the Calendar Settings.
var calendarId = '<your-calendar-id>@group.calendar.google.com';
//Configure the year range you want to syncrhonize, e.g.: [2006, 2017]
var years = [];

var dateFormat = 'M/d/yyyy H:mm';

var titleRowMap = {
  'title': 'Title',
  'description': 'Description',
  'location': 'Location',
  'starttime': 'Start Time',
  'endtime': 'End Time',
  'guests': 'Guests',
  'id': 'Id'
};
var titleRowKeys = ['title', 'description', 'location', 'starttime', 'endtime', 'guests', 'id'];
var requiredFields = ['id', 'title', 'starttime', 'endtime'];

// This controls whether email invites are sent to guests when the event is created in the
// calendar. Note that any changes to the event will cause email invites to be resent.
var SEND_EMAIL_INVITES = false;

// Adds the custom menu to the active spreadsheet.
function onOpen() {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var menuEntries = [
    {
      name: "Update from Calendar",
      functionName: "syncFromCalendar"
    }, {
      name: "Update to Calendar",
      functionName: "syncToCalendar"
    }
  ];
  spreadsheet.addMenu('Calendar Sync', menuEntries);
}

// Creates a mapping array between spreadsheet column and event field name
function createIdxMap(row) {
  var idxMap = [];
  for (var idx = 0; idx < row.length; idx++) {
    var fieldFromHdr = row[idx];
    for (var titleKey in titleRowMap) {
      if (titleRowMap[titleKey] == fieldFromHdr) {
        idxMap.push(titleKey);
        break;
      }
    }
    if (idxMap.length <= idx) {
      // Header field not in map, so add null
      idxMap.push(null);
    }
  }
  return idxMap;
}

// Converts a spreadsheet row into an object containing event-related fields
function reformatEvent(row, idxMap) {
  return row.reduce(function(event, value, idx) {
    if (idxMap[idx] != null) {
      event[idxMap[idx]] = value;
    }
    return event;
  }, {});
}

// Converts a calendar event to a psuedo-sheet event.
function convertCalEvent(calEvent) {
  convertedEvent = {
    'id': calEvent.getId(),
    'title': calEvent.getTitle(),
    'description': calEvent.getDescription(),
    'location': calEvent.getLocation(),
    'guests': calEvent.getGuestList().map(function(x) {return x.getEmail();}).join(',')
  };
  if (calEvent.isAllDayEvent()) {
    convertedEvent.starttime = calEvent.getAllDayStartDate();
    var endtime = calEvent.getAllDayEndDate();
    if (endtime - convertedEvent.starttime === 24 * 3600 * 1000) {
      convertedEvent.endtime = '';
    } else {
      convertedEvent.endtime = endtime;
      if (endtime.getHours() === 0 && endtime.getMinutes() == 0) {
        convertedEvent.endtime.setSeconds(endtime.getSeconds() - 1);
      }
    }
  } else {
    convertedEvent.starttime = calEvent.getStartTime();
    convertedEvent.endtime = calEvent.getEndTime();
  }
  return convertedEvent;
}

// Converts calendar event into spreadsheet data row
function calEventToSheet(calEvent, idxMap, dataRow) {
  convertedEvent = convertCalEvent(calEvent);

  for (var idx = 0; idx < idxMap.length; idx++) {
    if (idxMap[idx] !== null) {
      dataRow[idx] = convertedEvent[idxMap[idx]];
    }
  }
}

// Returns empty string or time in milliseconds for Date object
function getEndTime(ev) {
  return ev.endtime === '' ? '' : ev.endtime.getTime();
}

// Tests whether calendar event matches spreadsheet event
function eventMatches(cev, sev) {
  var convertedCalEvent = convertCalEvent(cev);
  return convertedCalEvent.title == sev.title &&
    convertedCalEvent.description == sev.description &&
    convertedCalEvent.location == sev.location &&
    convertedCalEvent.starttime.toString() == sev.starttime.toString() &&
    getEndTime(convertedCalEvent) === getEndTime(sev) &&
    convertedCalEvent.guests == sev.guests;
}

// Determine whether required fields are missing
function fieldsMissing(idxMap) {
  return requiredFields.some(function(val) {
    return idxMap.indexOf(val) < 0;
  });
}

// Set up formats and hide ID column for empty spreadsheet
function setUpSheet(sheet, fieldKeys) {
  sheet.getRange(1, fieldKeys.indexOf('starttime') + 1, 999).setNumberFormat(dateFormat);
  sheet.getRange(1, fieldKeys.indexOf('endtime') + 1, 999).setNumberFormat(dateFormat);
  sheet.hideColumns(fieldKeys.indexOf('id') + 1);
}

// Display error alert
function errorAlert(msg, evt, ridx) {
  var ui = SpreadsheetApp.getUi();
  if (evt) {
    ui.alert('Skipping row: ' + msg + ' in event "' + evt.title + '", row ' + (ridx + 1));
  } else {
    ui.alert(msg);
  }
}

function updateEvent(calEvent, sheetEvent){
  sheetEvent.sendInvites = SEND_EMAIL_INVITES;
  if (sheetEvent.endtime === '') {
    calEvent.setAllDayDate(sheetEvent.starttime);
  } else {
    calEvent.setTime(sheetEvent.starttime, sheetEvent.endtime);
  }
  calEvent.setTitle(sheetEvent.title);
  calEvent.setDescription(sheetEvent.description);
  calEvent.setLocation(sheetEvent.location);
  var guestCal = calEvent.getGuestList().map(function (x) {
    return {
      email: x.getEmail(),
      added: false
    };
  });
  var guests = sheetEvent.guests.split(',').map(function (x) {
    return x ? x.trim() : '';
  });
  //check guests that are already invited
  for (var gIx = 0; gIx < guestCal.length; gIx++) {
    var index = guests.indexOf(guestCal[gIx].email);
    if (index >= 0) {
      guestCal[gIx].added = true;
      guests.splice(index, 1);
    }
  }
  guests.forEach(function (x) {
    if (x) calEvent.addGuest(x);
  });
  guestCal.forEach(function (x) {
    if (!x.added) {
      calEvent.removeGuest(x.email);
    }
  });
}

// Synchronize from calendar to spreadsheet.
function syncFromCalendar() {
  // Get calendar and events
  var calendar = CalendarApp.getCalendarById(calendarId);
  var calEvents = calendar.getEvents(new Date('1/1/' + (years && years.length ? years[0] : '1970')), new Date('31/12/' + (years && years.length  ? years[years.length - 1] : '2030')));

  // Get spreadsheet and data
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getActiveSheet();
  var range = sheet.getDataRange();
  var data = range.getValues();
  var eventFound = new Array(data.length);

  // Check if spreadsheet is empty and add a title row
  var titleRow = [];
  for (var idx = 0; idx < titleRowKeys.length; idx++) {
    titleRow.push(titleRowMap[titleRowKeys[idx]]);
  }
  if (data.length < 1) {
    data.push(titleRow);
    range = sheet.getRange(1, 1, data.length, data[0].length);
    range.setValues(data);
    setUpSheet(sheet, titleRowKeys);
  }

  if (data.length == 1 && data[0].length == 1 && data[0][0] === '') {
    data[0] = titleRow;
    range = sheet.getRange(1, 1, data.length, data[0].length);
    range.setValues(data);
    setUpSheet(sheet, titleRowKeys);
  }

  // Map spreadsheet headers to indices
  var idxMap = createIdxMap(data[0]);
  var idIdx = idxMap.indexOf('id');

  // Verify header has all required fields
  if (fieldsMissing(idxMap)) {
    var reqFieldNames = requiredFields.map(function(x) {return titleRowMap[x];}).join(', ');
    errorAlert('Spreadsheet must have ' + reqFieldNames + ' columns');
    return;
  }

  // Array of IDs in the spreadsheet
  var sheetEventIds = data.slice(1).map(function(row) {return row[idIdx];});

  // Loop through calendar events
  for (var cidx = 0; cidx < calEvents.length; cidx++) {
    var calEvent = calEvents[cidx];
    var calEventId = calEvent.getId();

    var ridx = sheetEventIds.indexOf(calEventId) + 1;
    if (ridx < 1) {
      // Event not found, create it
      ridx = data.length;
      var newRow = [];
      var rowSize = idxMap.length;
      while (rowSize--) newRow.push('');
      data.push(newRow);
    } else {
      eventFound[ridx] = true;
    }
    // Update event in spreadsheet data
    calEventToSheet(calEvent, idxMap, data[ridx]);
  }

  // Remove any data rows not found in the calendar
  var rowsDeleted = 0;
  for (var idx = eventFound.length - 1; idx > 0; idx--) {
    //event doesn't exists and has an event id
    if (!eventFound[idx] && sheetEventIds[idx - 1]) {
      data.splice(idx, 1);
      rowsDeleted++;
    }
  }

  // Save spreadsheet changes
  range = sheet.getRange(1, 1, data.length, data[0].length);
  range.setValues(data);
  if (rowsDeleted > 0) {
    sheet.deleteRows(data.length + 1, rowsDeleted);
  }
}

// Synchronize from spreadsheet to calendar.
function syncToCalendar() {
  // Get calendar and events
  var calendar = CalendarApp.getCalendarById(calendarId);
  if (!calendar) {
    errorAlert('Cannot find calendar. Check instructions for set up.');
  }
  var calEvents = calendar.getEvents(new Date('1/1/' + (years && years.length  ? years[0] : '1970')), new Date('31/12/' + (years && years.length  ? years[years.length - 1] : '2030')));
  var calEventIds = calEvents.map(function(val) {return val.getId();});

  // Get spreadsheet and data
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getActiveSheet();
  var range = sheet.getDataRange();
  var data = range.getValues();
  if (data.length < 2) {
    errorAlert('Spreadsheet must have a title row and at least one data row');
    return;
  }

  // Map headers to indices
  var idxMap = createIdxMap(data[0]);
  var idIdx = idxMap.indexOf('id');
  var idRange = range.offset(0, idIdx, data.length, 1);
  var idData = idRange.getValues()

  // Verify header has all required fields
  if (fieldsMissing(idxMap)) {
    var reqFieldNames = requiredFields.map(function(x) {return titleRowMap[x];}).join(', ');
    errorAlert('Spreadsheet must have ' + reqFieldNames + ' columns');
    return;
  }

  // Loop through spreadsheet rows
  var numAdds = 0;
  var numUpdated = 0;
  var changesMade = false;
  for (var ridx = 1; ridx < data.length; ridx++) {
    var sheetEvent = reformatEvent(data[ridx], idxMap);

    // Do some error checking first
    if (!sheetEvent.title) {
      errorAlert('must have title', sheetEvent, ridx);
      continue;
    }
    if (!(sheetEvent.starttime instanceof Date)) {
      errorAlert('start time must be a date/time', sheetEvent, ridx);
      continue;
    }
    if (sheetEvent.endtime !== '') {
      if (!(sheetEvent.endtime instanceof Date)) {
        errorAlert('end time must be empty or a date/time', sheetEvent, ridx);
        continue;
      }
      if (sheetEvent.endtime < sheetEvent.starttime) {
        errorAlert('end time must be after start time for event', sheetEvent, ridx);
        continue;
      }
    }

    // Determine if spreadsheet event is already in calendar and matches
    var addEvent = true;
    if (sheetEvent.id) {
      var eventIdx = calEventIds.indexOf(sheetEvent.id);
      if (eventIdx >= 0) {
        calEventIds[eventIdx] = null;  // Prevents removing event below
        var calEvent = calEvents[eventIdx];
        if (!eventMatches(calEvent, sheetEvent)) {
          //update the event
          updateEvent(calEvent, sheetEvent);
      }
    }
    if (addEvent) {
      var newEvent;
      sheetEvent.sendInvites = SEND_EMAIL_INVITES;
      if (sheetEvent.endtime === '') {
        newEvent = calendar.createAllDayEvent(sheetEvent.title, sheetEvent.starttime, sheetEvent);
      } else {
        newEvent = calendar.createEvent(sheetEvent.title, sheetEvent.starttime, sheetEvent.endtime, sheetEvent);
      }
      // Put event ID back into spreadsheet
      idData[ridx][0] = newEvent.getId();
      changesMade = true;

      // Updating too many calendar events in a short time interval triggers an error. Still experimenting with
      // the exact values to use here, but this works for updating about 40 events.
      numAdds++;
      if (numAdds > 10) {
        Utilities.sleep(75);
      }
    }
  }

  // Save spreadsheet changes
  if (changesMade) {
    idRange.setValues(idData);
  }

  // Remove any calendar events not found in the spreadsheet
  var numToRemove = calEventIds.reduce(function(prevVal, curVal) {
    if (curVal !== null) {
      prevVal++;
    }
    return prevVal;
  }, 0);
  if (numToRemove > 0) {
    var ui = SpreadsheetApp.getUi();
    var response = ui.Button.YES;
    if (numToRemove > numUpdated) {
      response = ui.alert('Delete ' + numToRemove + ' calendar event(s) not found in spreadsheet?',
          ui.ButtonSet.YES_NO);
    }
    if (response == ui.Button.YES) {
      calEventIds.forEach(function(id, idx) {
        if (id != null) {
          calEvents[idx].deleteEvent();
          Utilities.sleep(20);
        }
      });
    }
  }
}
}
<|endoftext|>


<commit_before>// pages/api/revalidate.js

export default async function handler(req, res) {
  // should be secret, custom header coming in from Contentful
  let inboundRevalToken = req.headers['x-vercel-reval-key']

  // Check for secret to confirm this is a valid request
  if (!inboundRevalToken) {
    return res
      .status(401)
      .json({ message: 'x-vercel-reval-key header not defined' })
  } else if (inboundRevalToken !== process.env.CONTENTFUL_REVALIDATE_SECRET) {
    return res.status(401).json({ message: 'Invalid token' })
  }

  try {
    let postSlug = JSON.parse(req.body).fields.slug['en-US']

    // revalidate the individual post and the home page
    await res.revalidate(`/posts/${postSlug}`)
    await res.revalidate('/')

    return res.json({ revalidated: true })
  } catch (err) {
    // If there was an error, Next.js will continue
    // to show the last successfully generated page
    return res.status(500).send('Error revalidating')
  }
}
<commit_msg>Revert "Fix: Contentful webhook body parse." (#40925)<commit_after>// pages/api/revalidate.js

export default async function handler(req, res) {
  // should be secret, custom header coming in from Contentful
  let inboundRevalToken = req.headers['x-vercel-reval-key']

  // Check for secret to confirm this is a valid request
  if (!inboundRevalToken) {
    return res
      .status(401)
      .json({ message: 'x-vercel-reval-key header not defined' })
  } else if (inboundRevalToken !== process.env.CONTENTFUL_REVALIDATE_SECRET) {
    return res.status(401).json({ message: 'Invalid token' })
  }

  try {
    // Note: if this fails to parse you may have forget to set the
    // "content-type" header correctly as mentioned here https://github.com/vercel/next.js/blob/canary/examples/cms-contentful/README.md#step-9-try-using-on-demand-revalidation
    let postSlug = req.body.fields.slug['en-US']

    // revalidate the individual post and the home page
    await res.revalidate(`/posts/${postSlug}`)
    await res.revalidate('/')

    return res.json({ revalidated: true })
  } catch (err) {
    // If there was an error, Next.js will continue
    // to show the last successfully generated page
    return res.status(500).send('Error revalidating')
  }
}
<|endoftext|>


<commit_before>/**
 * http://www.openjs.com/scripts/events/keyboard_shortcuts/
 * Version : 2.01.B
 * By Binny V A
 * License : BSD
 */
shortcut = {
    'all_shortcuts':{},//All the shortcuts are stored in this array
    'add': function(shortcut_combination,callback,opt) {
        //Provide a set of default options
        var default_options = {
            'type':'keydown',
            'propagate':false,
            'disable_in_input':false,
            'target':document,
            'keycode':false
        }
        if(!opt) opt = default_options;
        else {
            for(var dfo in default_options) {
                if(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];
            }
        }

        var ele = opt.target;
        if(typeof opt.target == 'string') ele = document.getElementById(opt.target);
        var ths = this;
        shortcut_combination = shortcut_combination.toLowerCase();

        //The function to be called at keypress
        var func = function(e) {
            e = e || window.event;

            if(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields
                var element;
                if(e.target) element=e.target;
                else if(e.srcElement) element=e.srcElement;
                if(element.nodeType==3) element=element.parentNode;

                if(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;
            }

            //Find Which key is pressed
            if (e.keyCode) code = e.keyCode;
            else if (e.which) code = e.which;
            var character = String.fromCharCode(code).toLowerCase();

            if(code == 188) character=","; //If the user presses , when the type is onkeydown
            if(code == 190) character="."; //If the user presses , when the type is onkeydown

            var keys = shortcut_combination.split("+");
            //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked
            var kp = 0;

            //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken
            var shift_nums = {
                "`":"~",
                "1":"!",
                "2":"@",
                "3":"#",
                "4":"$",
                "5":"%",
                "6":"^",
                "7":"&",
                "8":"*",
                "9":"(",
                "0":")",
                "-":"_",
                "=":"+",
                ";":":",
                "'":"\"",
                ",":"<",
                ".":">",
                "/":"?",
                "\\":"|"
            }
            //Special Keys - and their codes
            var special_keys = {
                'esc':27,
                'escape':27,
                'tab':9,
                'space':32,
                'return':13,
                'enter':13,
                'backspace':8,

                'scrolllock':145,
                'scroll_lock':145,
                'scroll':145,
                'capslock':20,
                'caps_lock':20,
                'caps':20,
                'numlock':144,
                'num_lock':144,
                'num':144,

                'pause':19,
                'break':19,

                'insert':45,
                'home':36,
                'delete':46,
                'end':35,

                'pageup':33,
                'page_up':33,
                'pu':33,

                'pagedown':34,
                'page_down':34,
                'pd':34,

                'left':37,
                'up':38,
                'right':39,
                'down':40,

                'f1':112,
                'f2':113,
                'f3':114,
                'f4':115,
                'f5':116,
                'f6':117,
                'f7':118,
                'f8':119,
                'f9':120,
                'f10':121,
                'f11':122,
                'f12':123
            }

            var modifiers = {
                shift: { wanted:false, pressed:false},
                ctrl : { wanted:false, pressed:false},
                alt  : { wanted:false, pressed:false},
                meta : { wanted:false, pressed:false}   //Meta is Mac specific
            };

            if(e.ctrlKey)   modifiers.ctrl.pressed = true;
            if(e.shiftKey)  modifiers.shift.pressed = true;
            if(e.altKey)    modifiers.alt.pressed = true;
            if(e.metaKey)   modifiers.meta.pressed = true;

            for(var i=0; k=keys[i],i<keys.length; i++) {
                //Modifiers
                if(k == 'ctrl' || k == 'control') {
                    kp++;
                    modifiers.ctrl.wanted = true;

                } else if(k == 'shift') {
                    kp++;
                    modifiers.shift.wanted = true;

                } else if(k == 'alt') {
                    kp++;
                    modifiers.alt.wanted = true;
                } else if(k == 'meta') {
                    kp++;
                    modifiers.meta.wanted = true;
                } else if(k.length > 1) { //If it is a special key
                    if(special_keys[k] == code) kp++;

                } else if(opt['keycode']) {
                    if(opt['keycode'] == code) kp++;

                } else { //The special keys did not match
                    if(character == k) kp++;
                    else {
                        if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase
                            character = shift_nums[character];
                            if(character == k) kp++;
                        }
                    }
                }
            }

            if(kp == keys.length &&
                        modifiers.ctrl.pressed == modifiers.ctrl.wanted &&
                        modifiers.shift.pressed == modifiers.shift.wanted &&
                        modifiers.alt.pressed == modifiers.alt.wanted &&
                        modifiers.meta.pressed == modifiers.meta.wanted) {
                callback(e);

                if(!opt['propagate']) { //Stop the event
                    //e.cancelBubble is supported by IE - this will kill the bubbling process.
                    e.cancelBubble = true;
                    e.returnValue = false;

                    //e.stopPropagation works in Firefox.
                    if (e.stopPropagation) {
                        e.stopPropagation();
                        e.preventDefault();
                    }
                    return false;
                }
            }
        }
        this.all_shortcuts[shortcut_combination] = {
            'callback':func,
            'target':ele,
            'event': opt['type']
        };
        //Attach the function with the event
        if(ele.addEventListener) ele.addEventListener(opt['type'], func, false);
        else if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);
        else ele['on'+opt['type']] = func;
    },

    //Remove the shortcut - just specify the shortcut and I will remove the binding
    'remove':function(shortcut_combination) {
        shortcut_combination = shortcut_combination.toLowerCase();
        var binding = this.all_shortcuts[shortcut_combination];
        delete(this.all_shortcuts[shortcut_combination])
        if(!binding) return;
        var type = binding['event'];
        var ele = binding['target'];
        var callback = binding['callback'];

        if(ele.detachEvent) ele.detachEvent('on'+type, callback);
        else if(ele.removeEventListener) ele.removeEventListener(type, callback, false);
        else ele['on'+type] = false;
    }
};<commit_msg>Fix page errors during builds.<commit_after>/**
 * http://www.openjs.com/scripts/events/keyboard_shortcuts/
 * Version : 2.01.B
 * By Binny V A
 * License : BSD
 */
shortcut = {
    'all_shortcuts':{},//All the shortcuts are stored in this array
    'add': function(shortcut_combination,callback,opt) {
        //Provide a set of default options
        var default_options = {
            'type':'keydown',
            'propagate':false,
            'disable_in_input':false,
            'target':document,
            'keycode':false
        }
        if(!opt) opt = default_options;
        else {
            for(var dfo in default_options) {
                if(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];
            }
        }

        var ele = opt.target;
        if(typeof opt.target == 'string') ele = document.getElementById(opt.target);
        var ths = this;
        shortcut_combination = shortcut_combination.toLowerCase();

        //The function to be called at keypress
        var func = function(e) {
            e = e || window.event;

            if(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields
                var element;
                if(e.target) element=e.target;
                else if(e.srcElement) element=e.srcElement;
                if(element.nodeType==3) element=element.parentNode;

                if(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;
            }

            //Find Which key is pressed
            if (e.keyCode) code = e.keyCode;
            else if (e.which) code = e.which;
            else return;
            var character = String.fromCharCode(code).toLowerCase();

            if(code == 188) character=","; //If the user presses , when the type is onkeydown
            if(code == 190) character="."; //If the user presses , when the type is onkeydown

            var keys = shortcut_combination.split("+");
            //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked
            var kp = 0;

            //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken
            var shift_nums = {
                "`":"~",
                "1":"!",
                "2":"@",
                "3":"#",
                "4":"$",
                "5":"%",
                "6":"^",
                "7":"&",
                "8":"*",
                "9":"(",
                "0":")",
                "-":"_",
                "=":"+",
                ";":":",
                "'":"\"",
                ",":"<",
                ".":">",
                "/":"?",
                "\\":"|"
            }
            //Special Keys - and their codes
            var special_keys = {
                'esc':27,
                'escape':27,
                'tab':9,
                'space':32,
                'return':13,
                'enter':13,
                'backspace':8,

                'scrolllock':145,
                'scroll_lock':145,
                'scroll':145,
                'capslock':20,
                'caps_lock':20,
                'caps':20,
                'numlock':144,
                'num_lock':144,
                'num':144,

                'pause':19,
                'break':19,

                'insert':45,
                'home':36,
                'delete':46,
                'end':35,

                'pageup':33,
                'page_up':33,
                'pu':33,

                'pagedown':34,
                'page_down':34,
                'pd':34,

                'left':37,
                'up':38,
                'right':39,
                'down':40,

                'f1':112,
                'f2':113,
                'f3':114,
                'f4':115,
                'f5':116,
                'f6':117,
                'f7':118,
                'f8':119,
                'f9':120,
                'f10':121,
                'f11':122,
                'f12':123
            }

            var modifiers = {
                shift: { wanted:false, pressed:false},
                ctrl : { wanted:false, pressed:false},
                alt  : { wanted:false, pressed:false},
                meta : { wanted:false, pressed:false}   //Meta is Mac specific
            };

            if(e.ctrlKey)   modifiers.ctrl.pressed = true;
            if(e.shiftKey)  modifiers.shift.pressed = true;
            if(e.altKey)    modifiers.alt.pressed = true;
            if(e.metaKey)   modifiers.meta.pressed = true;

            for(var i=0; k=keys[i],i<keys.length; i++) {
                //Modifiers
                if(k == 'ctrl' || k == 'control') {
                    kp++;
                    modifiers.ctrl.wanted = true;

                } else if(k == 'shift') {
                    kp++;
                    modifiers.shift.wanted = true;

                } else if(k == 'alt') {
                    kp++;
                    modifiers.alt.wanted = true;
                } else if(k == 'meta') {
                    kp++;
                    modifiers.meta.wanted = true;
                } else if(k.length > 1) { //If it is a special key
                    if(special_keys[k] == code) kp++;

                } else if(opt['keycode']) {
                    if(opt['keycode'] == code) kp++;

                } else { //The special keys did not match
                    if(character == k) kp++;
                    else {
                        if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase
                            character = shift_nums[character];
                            if(character == k) kp++;
                        }
                    }
                }
            }

            if(kp == keys.length &&
                        modifiers.ctrl.pressed == modifiers.ctrl.wanted &&
                        modifiers.shift.pressed == modifiers.shift.wanted &&
                        modifiers.alt.pressed == modifiers.alt.wanted &&
                        modifiers.meta.pressed == modifiers.meta.wanted) {
                callback(e);

                if(!opt['propagate']) { //Stop the event
                    //e.cancelBubble is supported by IE - this will kill the bubbling process.
                    e.cancelBubble = true;
                    e.returnValue = false;

                    //e.stopPropagation works in Firefox.
                    if (e.stopPropagation) {
                        e.stopPropagation();
                        e.preventDefault();
                    }
                    return false;
                }
            }
        }
        this.all_shortcuts[shortcut_combination] = {
            'callback':func,
            'target':ele,
            'event': opt['type']
        };
        //Attach the function with the event
        if(ele.addEventListener) ele.addEventListener(opt['type'], func, false);
        else if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);
        else ele['on'+opt['type']] = func;
    },

    //Remove the shortcut - just specify the shortcut and I will remove the binding
    'remove':function(shortcut_combination) {
        shortcut_combination = shortcut_combination.toLowerCase();
        var binding = this.all_shortcuts[shortcut_combination];
        delete(this.all_shortcuts[shortcut_combination])
        if(!binding) return;
        var type = binding['event'];
        var ele = binding['target'];
        var callback = binding['callback'];

        if(ele.detachEvent) ele.detachEvent('on'+type, callback);
        else if(ele.removeEventListener) ele.removeEventListener(type, callback, false);
        else ele['on'+type] = false;
    }
};
<|endoftext|>


<commit_before>
// WineReview.js
// Author: Matthew Johnson  & David Wells

function WineReview(wine, friend){
	var global = require('ui/common/globals');
	var self = global.createWindow('');
	if(!global.android)
		self.barImage='images/iPhone_Nav_Bar_Bkgrd_With_Black.png';
	var all = wine.all_information;

	// Creates back button
	if(!global.android){
		var back = Ti.UI.createButton({ title: "Back" });
	 	back.addEventListener("click", function()
		{
	 		self.close({animated:true});
		});
		self.setLeftNavButton(back);
	}
	var overview = Ti.UI.createScrollView({
		height: Ti.UI.SIZE,
		width: Ti.UI.FILL,
		layout: 'vertical',
	});

	// Add the header to the view.
	var header = require('ui/handheld/Wine_Review/header');
	var head = header(
			wine.name,
			all.Vineyard.Name,
			all.Appellation.Name,
			all.Appellation.Region.Name,
			all.Labels[all.Labels.length - 1].Url
	);
	overview.add(head.header);
	var progressbar = Ti.UI.createProgressBar({width: Ti.UI.FILL, height: 20});

	var FriendsReviews = Ti.UI.createLabel({
		top: 5,
		left: 10,
  		color: global.colors.dark,
  		font: { fontFamily: 'Helvetica Neue', fontSize:18, fontWeight: 'bold'},
  		text: 'Reviews',
  		height: Ti.UI.SIZE,
  		width: Ti.UI.FILL
	});

	overview.add(FriendsReviews);
	get_checkin_view = require('ui/handheld/Wine_Review/Checkin');

	var ch = get_checkin_view(all);
	var dd = require('ui/common/elements/dropdown');
	var tableview = null;
	function load_tables(){
		//alert("wineid: "+ JSON.stringify(wine));
		var uid = null;
		if(friend)
			uid = friend.user_id;
		global.api.previous_checkins(wine.id, uid, function(data){
			//alert(JSON.stringify(data));
			if(tableview != null)
				overview.remove(tableview);
			tableview = Titanium.UI.createView({
				//data:reviews,
				width: Ti.UI.FILL,
				height: Ti.UI.SIZE,
				layout:'vertical',
				bottom: 10
			});
			var reviews = [];

			for (var i = 0; i < data.length; i++) {
				var review = data[i];

				// THIS IS ONE REVIEW ENTRY
				var rc = Ti.UI.createView({
					width: Ti.UI.FILL,
					height: Ti.UI.SIZE,
					top: 10,
					left: 10,
					right:10,
					borderRadius: 5,
					backgroundColor: '#fcf3e1',
					layout: 'horizontal',
					touchEnabled: true
				});

				var user_image = Ti.UI.createImageView({
			  		height: Ti.UI.SIZE,
			  		width: 60,
					top: 10,
			  		left: 10,
					borderWidth: 1,
					borderRadius: 10,
			  		clipsToBounds: true,
			  		image: review.friend.picture_url,
					touchEnabled: false

				});
				rc.add(user_image);
				var rv = Ti.UI.createView({
					layout: 'vertical',
					height: Ti.UI.SIZE,
					width: Ti.UI.FILL,
					touchEnabled: false
				});
				//r.add(rc);
				rc.add(rv);
				rv.add(Ti.UI.createLabel({
					color: 'black',
	    			top: 10,
	    			left: 10,
	    			right: 10,
					text: "Rating: "+review.rating + " by " +review.friend.fname+" "+review.friend.lname+ "\n" +review.date,
					font: {fontSize: 12, fontStyle: 'italic'},
					textAlign: Ti.UI.TEXT_ALIGNMENT_RIGHT,
					height: Ti.UI.SIZE,
					width: Ti.UI.FILL,
					touchEnabled: false
				}));
				review.upload_pic = null;
				if(review.wine_pic.length  > 0)
				{
					upload_pic = Ti.UI.createImageView({
						width: Ti.UI.FILL,
						left: 10, right: 10,
						top: 5,
						image: review.wine_pic,
						touchEnabled: false
					});
					rc.add(upload_pic);
					review.upload_pic = upload_pic;
				}
				rc.add(Ti.UI.createLabel({
					text: '"'+review.comment + '"',
					height: Ti.UI.SIZE,
					width: Ti.UI.FILL,
					textAlign: Ti.UI.TEXT_ALIGNMENT_CENTER,
					font: {fontSize: 12, fontStyle: 'italic'},
					bottom: 15,
					left: 10,
	    			right: 10,
					touchEnabled: false
				}));
				//review.friend;
				//  THIS IS WHERE THE SWIPE TO DELETE EVENT IS
				rc.addEventListener('swipe', function(r){
					if(r.direction != 'right') return;
					if(global.user_id == r.source.review.friend.ID){
   	 					//alert('You swiped your own review '+e.direction);
   	 					var confirm = Titanium.UI.createAlertDialog({ title: 'Delete this review?', message: 'Are you sure?\n(this cannot be undone)', buttonNames: ['Yes', 'No'], cancel: 1 });
						confirm.addEventListener('click', function(e) { Titanium.API.info('e = ' + JSON.stringify(e));
						   //Clicked cancel, first check is for iphone, second for android
						   if (e.cancel === e.index || e.cancel === true) {
						      return;
						   }

						    //now you can use parameter e to switch/case

						   switch (e.index) {
						      case 0: Titanium.API.info('Clicked button 0 (YES)');
						      //alert('checkin id'+ r.review.checkin_id);
						      	global.api.delete_review(r.source.review.checkin_id, function(){
						      		Ti.API.info('deleted: '+r.source.review.checkin_id);
						      	});
						      	r.source.width = r.source.size.width;
							      r.source.animate({left: Titanium.Platform.displayCaps.platformWidth,  duration: 200}, function(t){
							      	// r.source.height=0;
							      	// r.source.visible = false;
							      	// r.source.top = 0; r.source.bottom = 0;
							      	tableview.deleteRow(r.source.index);
							      });

						      break;

						      //This will never be reached, if you specified cancel for index 1
						      case 1: Titanium.API.info('Clicked button 1 (NO)');
						      break;

						      default:
						      break;

						  }
						});
						confirm.show();

   	 				}

				});

				//  THIS IS WHERE THE CLICK EVENT IS FOR WINE REVIEWS
				//  Used to edit your own wine revies
				rc.addEventListener('click', function(e){

					var open_review_details = require('/ui/handheld/review_details');

					var review_details = open_review_details(e.source.review);
					review_details.containingTab = self.containingTab;
					self.containingTab.open(review_details);
				});
				rc.review = review;
				tableview.add(rc);

			}
			// create table view

			overview.add(tableview);
		});
	};
	load_tables();
	function upload_image(id, img, total_rotation){
		if(!img){
			load_tables();
			return;
		}
		overview.add(progressbar);
		progressbar.show();
        var xhr = Titanium.Network.createHTTPClient();
        xhr.onsendstream = function(e){
		        progressbar.value = e.progress ;
		};
        xhr.onload = function(){
        	progressbar.hide();
        	            	Ti.API.info(this.responseText);

        	res = JSON.parse(this.responseText);
        	overview.remove(progressbar);
        	if(!res.success)
        		alert("Server Error: \""+res.error+"\" Please try again later.");
        	else
        		load_tables();
        }
        Ti.API.info('Uploading photo: ' + "http://winelife.ericwooley.com/user/upload/wine/"+id);
		xhr.open('POST', "http://winelife.ericwooley.com/user/upload/wine/"+id);
		//f1 = Titanium.Filesystem.getFile(Titanium.Filesystem.resourcesDirectory,filename);
		//iamge=f1.read(image);
		xhr.send({profile_image: img, rotation: total_rotation});
	};
	Ti.App.addEventListener('rotate', function(rotation){
		ch.image_rotation = rotation.r;
	});
	dd(ch.view, self, "Finish Check-In", "Check-In", "up", function(){
		ch.ta.blur();
		global.api.checkin(wine.id, ch.ta.value, Math.round(ch.rating.value), function(data){
			Ti.API.info('checkin complete:' + data.id);
			if(ch.ui == null){
				Ti.API.info('upload_image is null');
			}
			else{
				Ti.API.info('uploading image');
				upload_image(data.id, ch.ui.image, ch.image_rotation);
			}
			//load_tables();
		});
	});
	self.add(overview);
	return self;
};

module.exports = WineReview;<commit_msg>fixed swipe to delete<commit_after>
// WineReview.js
// Author: Matthew Johnson  & David Wells

function WineReview(wine, friend){
	var global = require('ui/common/globals');
	var self = global.createWindow('');
	if(!global.android)
		self.barImage='images/iPhone_Nav_Bar_Bkgrd_With_Black.png';
	var all = wine.all_information;

	// Creates back button
	if(!global.android){
		var back = Ti.UI.createButton({ title: "Back" });
	 	back.addEventListener("click", function()
		{
	 		self.close({animated:true});
		});
		self.setLeftNavButton(back);
	}
	var overview = Ti.UI.createScrollView({
		height: Ti.UI.SIZE,
		width: Ti.UI.FILL,
		layout: 'vertical',
	});

	// Add the header to the view.
	var header = require('ui/handheld/Wine_Review/header');
	var head = header(
			wine.name,
			all.Vineyard.Name,
			all.Appellation.Name,
			all.Appellation.Region.Name,
			all.Labels[all.Labels.length - 1].Url
	);
	overview.add(head.header);
	var progressbar = Ti.UI.createProgressBar({width: Ti.UI.FILL, height: 20});

	var FriendsReviews = Ti.UI.createLabel({
		top: 5,
		left: 10,
  		color: global.colors.dark,
  		font: { fontFamily: 'Helvetica Neue', fontSize:18, fontWeight: 'bold'},
  		text: 'Reviews',
  		height: Ti.UI.SIZE,
  		width: Ti.UI.FILL
	});

	overview.add(FriendsReviews);
	get_checkin_view = require('ui/handheld/Wine_Review/Checkin');

	var ch = get_checkin_view(all);
	var dd = require('ui/common/elements/dropdown');
	var tableview = null;
	function load_tables(){
		//alert("wineid: "+ JSON.stringify(wine));
		var uid = null;
		if(friend)
			uid = friend.user_id;
		global.api.previous_checkins(wine.id, uid, function(data){
			//alert(JSON.stringify(data));
			if(tableview != null)
				overview.remove(tableview);
			tableview = Titanium.UI.createView({
				//data:reviews,
				width: Ti.UI.FILL,
				height: Ti.UI.SIZE,
				layout:'vertical',
				bottom: 10
			});
			var reviews = [];

			for (var i = 0; i < data.length; i++) {
				var review = data[i];

				// THIS IS ONE REVIEW ENTRY
				var rc = Ti.UI.createView({
					width: Ti.UI.FILL,
					height: Ti.UI.SIZE,
					top: 10,
					left: 10,
					right:10,
					borderRadius: 5,
					backgroundColor: '#fcf3e1',
					layout: 'horizontal',
					touchEnabled: true
				});

				var user_image = Ti.UI.createImageView({
			  		height: Ti.UI.SIZE,
			  		width: 60,
					top: 10,
			  		left: 10,
					borderWidth: 1,
					borderRadius: 10,
			  		clipsToBounds: true,
			  		image: review.friend.picture_url,
					touchEnabled: false

				});
				rc.add(user_image);
				var rv = Ti.UI.createView({
					layout: 'vertical',
					height: Ti.UI.SIZE,
					width: Ti.UI.FILL,
					touchEnabled: false
				});
				//r.add(rc);
				rc.add(rv);
				rv.add(Ti.UI.createLabel({
					color: 'black',
	    			top: 10,
	    			left: 10,
	    			right: 10,
					text: "Rating: "+review.rating + " by " +review.friend.fname+" "+review.friend.lname+ "\n" +review.date,
					font: {fontSize: 12, fontStyle: 'italic'},
					textAlign: Ti.UI.TEXT_ALIGNMENT_RIGHT,
					height: Ti.UI.SIZE,
					width: Ti.UI.FILL,
					touchEnabled: false
				}));
				review.upload_pic = null;
				if(review.wine_pic.length  > 0)
				{
					upload_pic = Ti.UI.createImageView({
						width: Ti.UI.FILL,
						left: 10, right: 10,
						top: 5,
						image: review.wine_pic,
						touchEnabled: false
					});
					rc.add(upload_pic);
					review.upload_pic = upload_pic;
				}
				rc.add(Ti.UI.createLabel({
					text: '"'+review.comment + '"',
					height: Ti.UI.SIZE,
					width: Ti.UI.FILL,
					textAlign: Ti.UI.TEXT_ALIGNMENT_CENTER,
					font: {fontSize: 12, fontStyle: 'italic'},
					bottom: 15,
					left: 10,
	    			right: 10,
					touchEnabled: false
				}));
				//review.friend;
				//  THIS IS WHERE THE SWIPE TO DELETE EVENT IS
				rc.addEventListener('swipe', function(r){
					if(r.direction != 'right') return;
					if(global.user_id == r.source.review.friend.ID){
   	 					//alert('You swiped your own review '+e.direction);
   	 					var confirm = Titanium.UI.createAlertDialog({ title: 'Delete this review?', message: 'Are you sure?\n(this cannot be undone)', buttonNames: ['Yes', 'No'], cancel: 1 });
						confirm.addEventListener('click', function(e) { Titanium.API.info('e = ' + JSON.stringify(e));
						   //Clicked cancel, first check is for iphone, second for android
						   if (e.cancel === e.index || e.cancel === true) {
						      return;
						   }

						    //now you can use parameter e to switch/case

						   switch (e.index) {
						      case 0: Titanium.API.info('Clicked button 0 (YES)');
						      //alert('checkin id'+ r.review.checkin_id);
						      	global.api.delete_review(r.source.review.checkin_id, function(){
						      		Ti.API.info('deleted: '+r.source.review.checkin_id);
						      	});
						      	r.source.width = r.source.size.width;
							      r.source.animate({left: Titanium.Platform.displayCaps.platformWidth,  duration: 200}, function(t){
							      	// r.source.height=0;
							      	// r.source.visible = false;
							      	// r.source.top = 0; r.source.bottom = 0;
							      	tableview.remove(r.source);
							      });

						      break;

						      //This will never be reached, if you specified cancel for index 1
						      case 1: Titanium.API.info('Clicked button 1 (NO)');
						      break;

						      default:
						      break;

						  }
						});
						confirm.show();

   	 				}

				});

				//  THIS IS WHERE THE CLICK EVENT IS FOR WINE REVIEWS
				//  Used to edit your own wine revies
				rc.addEventListener('click', function(e){

					var open_review_details = require('/ui/handheld/review_details');

					var review_details = open_review_details(e.source.review);
					review_details.containingTab = self.containingTab;
					self.containingTab.open(review_details);
				});
				rc.review = review;
				tableview.add(rc);

			}
			// create table view

			overview.add(tableview);
		});
	};
	load_tables();
	function upload_image(id, img, total_rotation){
		if(!img){
			load_tables();
			return;
		}
		overview.add(progressbar);
		progressbar.show();
        var xhr = Titanium.Network.createHTTPClient();
        xhr.onsendstream = function(e){
		        progressbar.value = e.progress ;
		};
        xhr.onload = function(){
        	progressbar.hide();
        	            	Ti.API.info(this.responseText);

        	res = JSON.parse(this.responseText);
        	overview.remove(progressbar);
        	if(!res.success)
        		alert("Server Error: \""+res.error+"\" Please try again later.");
        	else
        		load_tables();
        }
        Ti.API.info('Uploading photo: ' + "http://winelife.ericwooley.com/user/upload/wine/"+id);
		xhr.open('POST', "http://winelife.ericwooley.com/user/upload/wine/"+id);
		//f1 = Titanium.Filesystem.getFile(Titanium.Filesystem.resourcesDirectory,filename);
		//iamge=f1.read(image);
		xhr.send({profile_image: img, rotation: total_rotation});
	};
	Ti.App.addEventListener('rotate', function(rotation){
		ch.image_rotation = rotation.r;
	});
	dd(ch.view, self, "Finish Check-In", "Check-In", "up", function(){
		ch.ta.blur();
		global.api.checkin(wine.id, ch.ta.value, Math.round(ch.rating.value), function(data){
			Ti.API.info('checkin complete:' + data.id);
			if(ch.ui == null){
				Ti.API.info('upload_image is null');
			}
			else{
				Ti.API.info('uploading image');
				upload_image(data.id, ch.ui.image, ch.image_rotation);
			}
			//load_tables();
		});
	});
	self.add(overview);
	return self;
};

module.exports = WineReview;<|endoftext|>


<commit_before>var App, find, visit, originalAdapter;

module("ember-testing Integration", {
  setup: function() {
    Ember.$('

').appendTo('body');
    Ember.run(function() {
      App = Ember.Application.create({
        rootElement: '#ember-testing'
      });

      App.Router.map(function() {
        this.resource("people", { path: "/" });
      });

      App.PeopleRoute = Ember.Route.extend({
        model: function() {
          return App.Person.find();
        }
      });

      App.PeopleView = Ember.View.extend({
        defaultTemplate: Ember.Handlebars.compile("{{#each person in controller}}
{{person.firstName}}
{{/each}}")
      });

      App.PeopleController = Ember.ArrayController.extend({});

      App.Person = Ember.Object.extend({
        firstName: ''
      });

      App.Person.reopenClass({
        find: function() {
          return Ember.A();
        }
      });

      App.ApplicationView = Ember.View.extend({
        defaultTemplate: Ember.Handlebars.compile("{{outlet}}")
      });

      App.setupForTesting();
    });

    Ember.run(function() {
      App.reset();
      App.deferReadiness();
    });

    App.injectTestHelpers();

    find = window.find;
    visit = window.visit;

    originalAdapter = Ember.Test.adapter;
  },

  teardown: function() {
    App.removeTestHelpers();
    Ember.$('#ember-testing-container, #ember-testing').remove();
    Ember.run(App, App.destroy);
    App = null;
    Ember.Test.adapter = originalAdapter;
  }
});

test("template is bound to array of 2 people", function() {
  App.Person.find = function() {
    var people = Ember.A();
    var first = App.Person.create({firstName: "x"});
    var last = App.Person.create({firstName: "y"});
    Ember.run(people, people.pushObject, first);
    Ember.run(people, people.pushObject, last);
    return people;
  };
  Ember.run(App, 'advanceReadiness');
  visit("/").then(function() {
    var rows = find(".name").length;
    equal(rows, 2, "successfully stubbed the find method for the / route");
  });
});
<commit_msg>updated ember-testing integration tests to show multiple scenarios<commit_after>var App, find, visit, originalAdapter;

module("ember-testing Integration", {
  setup: function() {
    Ember.$('

').appendTo('body');
    Ember.run(function() {
      App = Ember.Application.create({
        rootElement: '#ember-testing'
      });

      App.Router.map(function() {
        this.resource("people", { path: "/" });
      });

      App.PeopleRoute = Ember.Route.extend({
        model: function() {
          return App.Person.find();
        }
      });

      App.PeopleView = Ember.View.extend({
        defaultTemplate: Ember.Handlebars.compile("{{#each person in controller}}
{{person.firstName}}
{{/each}}")
      });

      App.PeopleController = Ember.ArrayController.extend({});

      App.Person = Ember.Object.extend({
        firstName: ''
      });

      App.Person.reopenClass({
        find: function() {
          return Ember.A();
        }
      });

      App.ApplicationView = Ember.View.extend({
        defaultTemplate: Ember.Handlebars.compile("{{outlet}}")
      });

      App.setupForTesting();
    });

    Ember.run(function() {
      App.reset();
      App.deferReadiness();
    });

    App.injectTestHelpers();

    find = window.find;
    visit = window.visit;

    originalAdapter = Ember.Test.adapter;
  },

  teardown: function() {
    App.removeTestHelpers();
    Ember.$('#ember-testing-container, #ember-testing').remove();
    Ember.run(App, App.destroy);
    App = null;
    Ember.Test.adapter = originalAdapter;
  }
});

test("template is bound to empty array of people", function() {
  App.Person.find = function() {
    return Ember.A();
  };
  Ember.run(App, 'advanceReadiness');
  visit("/").then(function() {
    var rows = find(".name").length;
    equal(rows, 0, "successfully stubbed an empty array of people");
  });
});

test("template is bound to array of 2 people", function() {
  App.Person.find = function() {
    var people = Ember.A();
    var first = App.Person.create({firstName: "x"});
    var last = App.Person.create({firstName: "y"});
    Ember.run(people, people.pushObject, first);
    Ember.run(people, people.pushObject, last);
    return people;
  };
  Ember.run(App, 'advanceReadiness');
  visit("/").then(function() {
    var rows = find(".name").length;
    equal(rows, 2, "successfully stubbed a non empty array of people");
  });
});

test("template is again bound to empty array of people", function() {
  App.Person.find = function() {
    return Ember.A();
  };
  Ember.run(App, 'advanceReadiness');
  visit("/").then(function() {
    var rows = find(".name").length;
    equal(rows, 0, "successfully stubbed another empty array of people");
  });
});
<|endoftext|>


<commit_before>import run from 'ember-runloop';
import {isBlank} from 'ember-utils';
import Component from 'ember-component';
import {invokeAction} from 'ember-invoke-action';

export default Component.extend({
    open() {
        this.get('select.actions').open();
    },

    close() {
        this.get('select.actions').close();
    },

    actions: {
        captureMouseDown(e) {
            e.stopPropagation();
        },

        search(term) {
            if (isBlank(term) === this.get('select.isOpen')) {
                run.scheduleOnce('afterRender', this, isBlank(term) ? this.close : this.open);
            }

            invokeAction(this, 'select.actions.search', term);
        },

        focusInput() {
            this.$('input')[0].focus();
        },

        resetInput() {
            this.$('input').val('');
        },

        handleKeydown(e) {
            let select = this.get('select');
            if (!select.isOpen) {
                e.stopPropagation();
            }
        }
    }
});
<commit_msg>:bug: fix typing a space in search input (#261)<commit_after>import run from 'ember-runloop';
import {isBlank} from 'ember-utils';
import Component from 'ember-component';
import {invokeAction} from 'ember-invoke-action';

export default Component.extend({
    open() {
        this.get('select.actions').open();
    },

    close() {
        this.get('select.actions').close();
    },

    actions: {
        captureMouseDown(e) {
            e.stopPropagation();
        },

        search(term) {
            if (isBlank(term) === this.get('select.isOpen')) {
                run.scheduleOnce('afterRender', this, isBlank(term) ? this.close : this.open);
            }

            invokeAction(this, 'select.actions.search', term);
        },

        focusInput() {
            this.$('input')[0].focus();
        },

        resetInput() {
            this.$('input').val('');
        },

        handleKeydown(e) {
            let select = this.get('select');

            // TODO: remove keycode check once EPS is updated to 1.0
            if (!select.isOpen || e.keyCode === 32) {
                e.stopPropagation();
            }
        }
    }
});
<|endoftext|>