Merging multiple Google calendar feeds into one JSON object in javascript - javascript
I am trying to bring in the JSON feeds from multiple Google calendars so that I can sort the upcoming events and display the next X number in an "Upcoming Events" list.
I have this working with Yahoo! pipes but I want to get away from using a 3rd party to aggregate. I think I am close, but I cannot get the JSON objects created correctly. I am getting the data into the array but not in JSON format, so I can't manipulate it.
I have tried var myJsonString = JSON.stringify(JSONData); using https://github.com/douglascrockford/JSON-js but that just threw errors. I suspect because my variable is in the wrong starting format. I have tried just calling the feed like: $.getJSON(url); and creating a function concant1() to do the JSONData=JSONData.concat(data);, but it doesn't fire and I think it would produce the same end result anyway. I have also tried several other methods of getting the end result I want with varying degrees of doom. Here is the closest I have come so far:
var JSONData = new Array();
var urllist = ["https://www.google.com/calendar/feeds/dg61asqgqg4pust2l20obgdl64%40group.calendar.google.com/public/full?orderby=starttime&max-results=3&sortorder=ascending&futureevents=true&ctz=America/New_York&singleevents=true&alt=json&callback=concant1","https://www.google.com/calendar/feeds/5oc3kvp7lnu5rd4krg2skcu2ng%40group.calendar.google.com/public/full?orderby=starttime&max-results=3&sortorder=ascending&futureevents=true&ctz=America/New_York&singleevents=true&alt=json&callback=concant1","http://www.google.com/calendar/feeds/rine4umu96kl6t46v4fartnho8%40group.calendar.google.com/public/full?orderby=starttime&max-results=3&sortorder=ascending&futureevents=true&ctz=America/New_York&singleevents=true&alt=json&callback=concant1"];
urllist.forEach(function addFeed(url){
alert("The URL being used: "+ url);
if (void 0 != JSONData){JSONData=JSONData.concat($.getJSON(url));}
else{JSONData = $.getJSON(url);}
alert("The count from concantonated JSONData: "+JSONData.length);
});
document.write("The final count from JSONData: "+JSONData.length+"<p>");
console.log(JSONData)
UPDATE:
Now with full working source!! :) If anyone would like to make suggestions on how to improve the code's efficiency it would be gratefully accepted. I hope others find this useful.:
// GCal MFA - Google Calendar Multiple Feed Aggregator
// Useage: GCalMFA(CIDs,n);
// Where 'CIDs' is a list of comma seperated Google calendar IDs in the format: id#group.calendar.google.com, and 'n' is the number of results to display.
// While the contained console.log(); outputs are really handy for testing, you will probably want to remove them for regular usage
// Author: Jeramy Kruser - http://jeramy.kruser.me
// This is error-checking code for IE and can be removed
// onerror=function (d, f, g){alert (d+ "\n"+ f+ "\n");}
// This keeps IE from complaining about console.log and can be removed if all the console.log testing statements are removed
// if (!window.console) {console = {log: function() {}};}
// Add a tag to your page to identify it as js-enabled for CSS purposes
document.body.className += ' js-enabled';
// Global variables
var urllist = [];
var maxResults = 3; // The default is 3 results unless a value is sent
var JSONData = {};
var eventCount = 0;
var errorLog = "";
JSONData = { count: 0,
value : {
description: "Aggregates multiple Google calendar feeds into a single sorted list",
generator: "StackOverflow communal coding - Thanks for the assist Patrick M",
website: "http://jeramy.kruser.me",
author: "Jeramy & Kasey Kruser",
items: []
}};
// Prototype forEach required for IE
if ( !Array.prototype.forEach ) {
Array.prototype.forEach = function(fn, scope) {
for(var i = 0, len = this.length; i < len; ++i) {
fn.call(scope, this[i], i, this);
}
}
}
// For putting dates from feed into a format that can be read by the Date function for calculating event length.
function parse (str) {
// validate year as 4 digits, month as 01-12, and day as 01-31
str = str.match (/^(\d{4})(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])$/);
if (str) {
// make a date
str[0] = new Date ( + str[1], + str[2] - 1, + str[3]);
// check if month stayed the same (ie that day number is valid)
if (str[0].getMonth () === + str[2] - 1) {
return str[0];
}
}
return undefined;
}
//For outputting to HTML
function output() {
var months, day_in_ms, summary, i, item, eventlink, title, calendar, where,dtstart, dtend, endyear, endmonth, endday, startyear, startmonth, startday, endmonthdayyear, eventlinktitle, startmonthday, length, curtextval, k;
// Array of month names from numbers for page display.
months = {'0':'January', '1':'February', '2':'March', '3':'April', '4':'May', '5':'June', '6':'July', '7':'August', '8':'September', '9':'October', '10':'November', '11':'December'};
// For use in calculating event length.
day_in_ms = 24 * 60 * 60 * 1000;
// Instantiate HTML Arrays.
summary = [];
for (i = 0; i < maxResults; i+=1 ) {
// console.log("i: "+i+" < "+"maxResults: "+ maxResults);
if (!(JSONData.value.items[i] === undefined)) {
item = JSONData.value.items[i];
// Grabbing data for each event in the feed.
eventlink = (item.link[0].href);
title = item.title.$t;
// Only display the calendar title if there is more than one
calendar = "";
if (urllist.length > 1) {
calendar = '<br />Calendar: <a href="https://www.google.com/calendar/embed?src=' + item.gd$who[0].email + '&ctz=America/New_York">' + item.gd$who[0].valueString + '<\/a> (<a href="https://www.google.com/calendar/ical/' + item.gd$who[0].email + '/public/basic.ics">iCal<\/a>)';
}
// Grabbing event location, if entered.
if ( item.gd$where[0].valueString !== "" ) {
where = '<br />' + (item.gd$where[0].valueString);
}
else {
where = ("");
}
// Grabbing start date and putting in form YYYYmmdd. Subtracting one day from dtend without a specified end time (which contains colons) to fix Google's habit of ending an all-day event at midnight on the following day.
dtstart = new Date(parse(((item.gd$when[0].startTime).substring(0,10)).replace(/-/g,"")));
if((item.gd$when[0].endTime).indexOf(':') === -1) {
dtend = new Date(parse(((item.gd$when[0].endTime).substring(0,10)).replace(/-/g,"")) - day_in_ms);
}
else {
dtend = new Date(parse(((item.gd$when[0].endTime).substring(0,10)).replace(/-/g,"")));
}
// Put dates in pretty form for display.
endyear = dtend.getFullYear();
endmonth = months[dtend.getMonth()];
endday = dtend.getDate();
startyear = dtstart.getFullYear();
startmonth = months[dtstart.getMonth()];
startday = dtstart.getDate();
//consolidate some much-used variables for HTML output.
endmonthdayyear = endmonth + ' ' + endday + ', ' + endyear;
eventlinktitle = '<a href="' + eventlink + '">' + title + '<\/a>';
startmonthday = startmonth + ' ' + startday;
// Calculates the number of days between each event's start and end dates.
length = ((dtend - dtstart) / day_in_ms);
// HTML for each event, depending on which div is available on the page (different HTML applies). Only one div can exist on any one page.
if (document.getElementById("homeCalendar") !== null ) {
// If the length of the event is greater than 0 days, show start and end dates.
if ( length > 0 && startmonth !== endmonth && startday === endday ) {
summary[i] = ('<h3>' + eventlink + '">' + startmonthday + ', ' + startyear + ' - ' + endmonthdayyear + '<\/a><\/h3><p>' + title + '<\/p>'); }
// If the length of the event is greater than 0 and begins and ends within the same month, shorten the date display.
else if ( length > 0 && startmonth === endmonth && startyear === endyear ) {
summary[i] = ('<h3><a href="' + eventlink + '">' + startmonthday + '-' + endday + ', ' + endyear + '<\/a><\/h3><p>' + title + '<\/p>'); }
// If the length of the event is greater than 0 and begins and ends within different months of the same year, shorten the date display.
else if ( length > 0 && startmonth !== endmonth && startyear === endyear ) {
summary[i] = ('<h3><a href="' + eventlink + '">' + startmonthday + ' - ' + endmonthdayyear + '<\/a><\/h3><p>' + title + '<\/p>'); }
// If the length of the event is less than one day (length < = 0), show only the start date.
else {
summary[i] = ('<h3><a href="' + eventlink + '">' + startmonthday + ', ' + startyear + '<\/a><\/h3><p>' + title + '<\/p>'); }
}
else if (document.getElementById("allCalendar") !== null ) {
// If the length of the event is greater than 0 days, show start and end dates.
if ( length > 0 && startmonth !== endmonth && startday === endday ) {
summary[i] = ('<li>' + eventlinktitle + '<br />' + startmonthday + ', ' + startyear + ' - ' + endmonthdayyear + where + calendar + '<\/li>'); }
// If the length of the event is greater than 0 and begins and ends within the same month, shorten the date display.
else if ( length > 0 && startmonth === endmonth && startyear === endyear ) {
summary[i] = ('<li>' + eventlinktitle + '<br />' + startmonthday + '-' + endday + ', ' + endyear + where + calendar + '<\/li>'); }
// If the length of the event is greater than 0 and begins and ends within different months of the same year, shorten the date display.
else if ( length > 0 && startmonth !== endmonth && startyear === endyear ) {
summary[i] = ('<li>' + eventlinktitle + '<br />' + startmonthday + ' - ' + endmonthdayyear + where + calendar + '<\/li>'); }
// If the length of the event is less than one day (length < = 0), show only the start date.
else {
summary[i] = ('<li>' + eventlinktitle + '<br />' + startmonthday + ', ' + startyear + where + calendar + '<\/li>'); }
}
}
if (summary[i] === undefined) { summary[i] = "";}
// console.log(summary[i]);
}
// console.log(JSONData);
// Puts the HTML into the div with the appropriate id. Each page can have only one.
if (document.getElementById("homeCalendar") !== null ) {
curtextval = document.getElementById("homeCalendar");
// console.log("homeCalendar: "+curtextval);
}
else if (document.getElementById("oneCalendar") !== null ) {
curtextval = document.getElementById("oneCalendar");
// console.log("oneCalendar: "+curtextval);
}
else if (document.getElementById("allCalendar") !== null ) {
curtextval = document.getElementById("allCalendar");
// console.log("allCalendar: "+curtextval.innerHTML);
}
for (k = 0; k<maxResults; k+=1 ) { curtextval.innerHTML = curtextval.innerHTML + summary[k]; }
if (JSONData.count === 0) {
errorLog += '<div id="noEvents">No events found.</div>';
}
if (document.getElementById("homeCalendar") === null ) {
curtextval.innerHTML = '<ul>' + curtextval.innerHTML + '<\/ul>';
}
if (errorLog !== "") {
curtextval.innerHTML += errorLog;
}
}
// For taking in each feed, breaking out the events and sorting them into the object by date
function sortFeed(event) {
var tempEntry, i;
tempEntry = event;
i = 0;
// console.log("*** New incoming event object #"+eventCount+" ***");
// console.log(event.title.$t);
// console.log(event);
// console.log("i = " + i + " and maxResults " + maxResults);
while(i<maxResults) {
// console.log("i = " + i + " < maxResults " + maxResults);
// console.log("Sorting event = " + event.title.$t + " by date of " + event.gd$when[0].startTime.substring(0,10).replace(/-/g,""));
if (JSONData.value.items[i]) {
// console.log("JSONData.value.items[" + i + "] exists and has a startTime of " + JSONData.value.items[i].gd$when[0].startTime.substring(0,10).replace(/-/g,""));
if (event.gd$when[0].startTime.substring(0,10).replace(/-/g,"")<JSONData.value.items[i].gd$when[0].startTime.substring(0,10).replace(/-/g,"")) {
// console.log("The incoming event value of " + event.gd$when[0].startTime.substring(0,10).replace(/-/g,"") + " is < " + JSONData.value.items[i].gd$when[0].startTime.substring(0,10).replace(/-/g,""));
tempEntry = JSONData.value.items[i];
// console.log("Existing JSONData.value.items[" + i + "] value " + JSONData.value.items[i].gd$when[0].startTime.substring(0,10).replace(/-/g,"") + " stored in tempEntry");
JSONData.value.items[i] = event;
// console.log("Position JSONData.value.items[" + i + "] set to new value: " + event.gd$when[0].startTime.substring(0,10).replace(/-/g,""));
event = tempEntry;
// console.log("Now sorting event = " + event.title.$t + " by date of " + event.gd$when[0].startTime.substring(0,10).replace(/-/g,""));
}
else {
// console.log("The incoming event value of " + event.gd$when[0].startTime.substring(0,10).replace(/-/g,"") + " is > " + JSONData.value.items[i].gd$when[0].startTime.substring(0,10).replace(/-/g,"") + " moving on...");
}
}
else {
JSONData.value.items[i] = event;
// console.log("JSONData.value.items[" + i + "] does not exist so it was set to the Incoming value of " + event.gd$when[0].startTime.substring(0,10).replace(/-/g,""));
i = maxResults;
}
i += 1;
}
}
// For completing the aggregation
function complete(result) {
// Track the number of calls completed back, we're not done until all URLs have processed
if( complete.count === undefined ){
complete.count = urllist.length;
}
// console.log("complete.count = "+complete.count);
// console.log(result.feed);
if(result.feed.entry){
JSONData.count = maxResults;
// Check each incoming item against JSONData.value.items
// console.log("*** Begin Sorting " + result.feed.entry.length + " Events ***");
// console.log(result.feed.entry);
result.feed.entry.forEach(
function(event){
eventCount += 1;
sortFeed(event);
}
);
}
if( (complete.count-=1)<1 ) {
// console.log("*** Done Sorting ***");
output();
}
}
// This is the main function. It takes in the list of Calendar IDs and the number of results to display
function GCalMFA(list,results){
var i, calPreProperties, calPostProperties1, calPostProperties2;
calPreProperties = "https://www.google.com/calendar/feeds/";
calPostProperties1 = "/public/full?max-results=";
calPostProperties2 = "&orderby=starttime&sortorder=ascending&futureevents=true&ctz=America/New_York&singleevents=true&alt=json&callback=?";
if (list) {
if (results) {
maxResults = results;
}
urllist = list.split(',');
for (i = 0; i < urllist.length; i+=1 ){
// console.log(urllist[i]);
if (urllist[i] === ""){ urllist.splice(i,1);}
else{
urllist[i] = calPreProperties + urllist[i] + calPostProperties1+maxResults+calPostProperties2;}
}
// console.log("There are " + urllist.length + " URLs");
urllist.forEach(function addFeed(url){
$.getJSON(url, complete);
});
}
else {
errorLog += '<div id="noURLs">No calendars have been selected.</div>';
output();
}
}
All right, here's the gist of what needs to change.
Updated fiddle: http://jsfiddle.net/ynuQ5/2/
Don't concat on the return value of $.getJSON. As I mentioned above, that gets you the XMLHttpRequest object, which is a lot more than the data you're interested in. Critically, however, at that point the request hasn't been made and the data isn't available yet.
Instead, handle it in callback for the AJAX request. I updated your URL list to use &callback=?, initialize the JSONData var to look more like the structure in your 2nd screenshot and then changed the javascript for the AJAX requests to this:
var JSONData = { count: 0,
value : {
description: "Calendars from the Unitarian Universalist Association (UUA.org)",
generator: "StackOverflow communal coding",
items: []
}};
// url list declaration goes here
urllist.forEach(function addFeed(url){
$.getJSON(url, function(result) {
if(!result.feed.entry) {
console.log("No entries from " + url);
return;
}
JSONData.count += result.feed.entry.length;
JSONData.value.items = JSONData.value.items.concat(result.feed.entry);
console.log(JSONData);
});
});
Right away you'll notice there are still some discrepancies between the raw data you get back from google and the data provided by the Yahoo pipe transform. Noticeably, a lot of their provided values have been transformed from objects to texts. For example, google gives us this:
id: Object
$t: "http://www.google.com/calendar/feeds/5oc3kvp7lnu5rd4krg2skcu2ng%40group.calendar.google.com/public/full/bbidp5qb4vh5vk9apok1cpnino_20130119"
link: Array[2]
0: Object
href: "https://www.google.com/calendar/event?eid=YmJpZHA1cWI0dmg1dms5YXBvazFjcG5pbm9fMjAxMzAxMTkgNW9jM2t2cDdsbnU1cmQ0a3JnMnNrY3UybmdAZw"
rel: "alternate"
title: "alternate"
type: "text/html"
1: Object
length: 2
published: Object
$t: "2012-11-13T15:59:31.000-05:00"
title: Object
$t: "30 Days of Love"
type: "text"
updated: Object
$t: "2012-11-13T15:59:31.000-05:00"
Where as your yahoo transform returns data more like this:
id: "http://www.google.com/calendar/feeds/5oc3kvp7lnu5rd4krg2skcu2ng%40group.calendar.google.com/public/full/bbidp5qb4vh5vk9apok1cpnino_20130119"
link: "href: "https://www.google.com/calendar/event?eid=YmJpZHA1cWI0dmg1dms5YXBvazFjcG5pbm9fMjAxMzAxMTkgNW9jM2t2cDdsbnU1cmQ0a3JnMnNrY3UybmdAZw"
published: "2012-11-13T15:59:31.000-05:00"
title: "30 Days of Love"
updated: "2012-11-13T15:59:31.000-05:00"
You can transform the data more when you receive it. Or you can modify your display code to use the more convoluted, raw values.
Let me know if I can clear anything up in my code or response.
Edit: Updated fiddle showing how to access author (aka feed name, apparently), start time and title: http://jsfiddle.net/ynuQ5/8/
Let me know if there's more specific stuff you want out of it :-)
Related
Resolve 'Parsing Error: Please check your selector. (line XX)' Javascript/AWQL
First off, let me say that I am not a developer, nor do I really code beyond basic HTML. So I appreciate your patience. :) I'm working with a script that is for AdWords, but I believe it's more or less written in Javascript. (I've included the script below.) Basically, I'm receiving the error message 'Parsing Error: Please check your selector. (line XX)' when I preview the script. I've searched all around for hours and have yet to find a solution. I think it may be that a query being returned contains either a single or double quote, and may be messing up the code? Though I can't actually prove that. Also, yes, I was sure to update lines 17-21 with the correct details. Any help would be much appreciated! Thanks! John /* // AdWords Script: Put Data From AdWords Report In Google Sheets // -------------------------------------------------------------- // Copyright 2017 Optmyzr Inc., All Rights Reserved // // This script takes a Google spreadsheet as input. Based on the column headers, data filters, and date range specified // on this sheet, it will generate different reports. // // The goal is to let users create custom automatic reports with AdWords data that they can then include in an automated reporting // tool like the one offered by Optmyzr. // // // For more PPC management tools, visit www.optmyzr.com // */ var DEBUG = 0; // set to 1 to get more details about what the script does while it runs; default = 0 var REPORT_SHEET_NAME = "report"; // the name of the tab where the report data should go var SETTINGS_SHEET_NAME = "settings"; // the name of the tab where the filters and date range are specified var SPREADSHEET_URL = "https://docs.google.com/spreadsheets/d/1dttJTb547L81XYKdTQ56LcfO9hHhbb9wm06ZY5mKhEo/edit#gid=0"; // The URL to the Google spreadsheet with your report template var EMAIL_ADDRESSES = "example#example.com"; // Get notified by email at this address when a new report is ready function main() { var currentSetting = new Object(); currentSetting.ss = SPREADSHEET_URL; // Read Settings Sheet var settingsSheet = SpreadsheetApp.openByUrl(currentSetting.ss).getSheetByName(SETTINGS_SHEET_NAME); var rows = settingsSheet.getDataRange(); var numRows = rows.getNumRows(); var numCols = rows.getNumColumns(); var values = rows.getValues(); var numSettingsRows = numRows - 1; var sortString = ""; var filters = new Array(); for(var i = 0; i < numRows; i++) { var row = values[i]; var settingName = row[0]; var settingOperator = row[1]; var settingValue = row[2]; var dataType = row[3]; debug(settingName + " " + settingOperator + " " + settingValue); if(settingName.toLowerCase().indexOf("report type") != -1) { var reportType = settingValue; } else if(settingName.toLowerCase().indexOf("date range") != -1) { var dateRange = settingValue; } else if(settingName.toLowerCase().indexOf("sort order") != -1) { var sortDirection = dataType || "DESC"; if(settingValue) var sortString = "ORDER BY " + settingValue + " " + sortDirection; var sortColumnIndex = 1; }else { if(settingOperator && settingValue) { if(dataType.toLowerCase().indexOf("long") != -1 || dataType.toLowerCase().indexOf("double") != -1 || dataType.toLowerCase().indexOf("money") != -1 || dataType.toLowerCase().indexOf("integer") != -1) { var filter = settingName + " " + settingOperator + " " + settingValue; } else { if(settingValue.indexOf("'") != -1) { var filter = settingName + " " + settingOperator + ' "' + settingValue + '"'; } else if(settingValue.indexOf("'") != -1) { var filter = settingName + " " + settingOperator + " '" + settingValue + "'"; } else { var filter = settingName + " " + settingOperator + " '" + settingValue + "'"; } } debug("filter: " + filter) filters.push(filter); } } } // Process the report sheet and fill in the data var reportSheet = SpreadsheetApp.openByUrl(currentSetting.ss).getSheetByName(REPORT_SHEET_NAME); var rows = reportSheet.getDataRange(); var numRows = rows.getNumRows(); var numCols = rows.getNumColumns(); var values = rows.getValues(); var numSettingsRows = numRows - 1; // Read Header Row and match names to settings var headerNames = new Array(); var row = values[0]; for(var i = 0; i < numCols; i++) { var value = row[i]; headerNames.push(value); //debug(value); } if(reportType.toLowerCase().indexOf("performance") != -1) { var dateString = ' DURING ' + dateRange; } else { var dateString = ""; } if(filters.length) { var query = 'SELECT ' + headerNames.join(",") + ' FROM ' + reportType + ' WHERE ' + filters.join(" AND ") + dateString + " " + sortString; } else { var query = 'SELECT ' + headerNames.join(",") + ' FROM ' + reportType + dateString + " " + sortString; } debug(query); var report = AdWordsApp.report(query); //THIS IS LINE 103 WITH THE ERROR try { report.exportToSheet(reportSheet); var subject = "Your " + reportType + " for " + dateRange + " for " + AdWordsApp.currentAccount().getName() + " is ready"; var body = "currentSetting.ss<br>You can now add this data to <a href='https://www.optmyzr.com'>Optmyzr</a> or another reporting system."; MailApp.sendEmail(EMAIL_ADDRESSES, subject, body); Logger.log("Your report is ready at " + currentSetting.ss); Logger.log("You can include this in your scheduled Optmyzr reports or another reporting tool."); } catch (e) { debug("error: " + e); } } function debug(text) { if(DEBUG) Logger.log(text); }
The area between SELECT and FROM is the selector. You're not selecting any fields with that query. That's happening because the headerNames array is empty. Verify the value of REPORT_SHEET_NAME
Loop inside loop producing wrong result
I'm having trouble producing a script to match an object's value in object array based on an object's value in a separate array, and retrieve a separate value from that object. I have used standard for-loops and the current iteration in jQuery each. I have also tried setting the if statement to look for the two values as ==, but it always produces non matches (or -1). Can anyone steer me in the right direction here? transfers = [ {Package: "1", Origin_Facility = "a"}, {Package: "2", Origin_Facility = "b"} ]; storeData = [ {fromPackage: "1,6,26"} ] var storeDataEach = function( sx, sxv ) { var transfersEach = function( sy, syv ) { if(storeData[sx].fromPackage.indexOf(transfers[sy].Package) > -1){ var facilityStore = transfers[sx].Origin_Facility; storeData[sx].origin = facilityStore + " + " + transfers[sy].Package + ' + ' + storeData[sx].fromPackage; return false; } else {storeData[sx].origin = 'error' + transfers[sy].Package + " + " + storeData[sx].fromPackage;return false;} }; jQuery.each(transfers, transfersEach); } jQuery.each(storeData, storeDataEach);
The main problem is you are returning false from the $.each loop which will stop the iteration A crude fix is to remove the return from else block var storeDataEach = function(sx, sxv) { var transfersEach = function(sy, syv) { if (storeData[sx].fromPackage.indexOf(transfers[sy].Package) > -1) { var facilityStore = transfers[sx].Origin_Facility; storeData[sx].origin = facilityStore + " + " + transfers[sy].Package + ' + ' + storeData[sx].fromPackage; return false; } else { storeData[sx].origin = 'error' + transfers[sy].Package + " + " + storeData[sx].fromPackage; } }; jQuery.each(transfers, transfersEach); } But this still have problems with the data structure, in your example you have 26 in the fromPackage, now if you have a package value of 2 that also will return a positive result
Adding new line after bracket
I am proxying the function console.log to add some information to my logs and I am as well checking whether the information being logged is an object. I do this to avoid getting a log entry of the sort 2016-12-17 (22:12:51) > [object Object] Code works fine when passing arguments that are not objects. For example, the command console.log("hello","world"); prints 2016-12-17 (22:23:53) > hello 2016-12-17 (22:23:53) > world But if I pass an object as well, the code will fail to insert a new line after the object. For example, the command console.log("hello",{world:true,hello:{amount:1,text:"hello"}},"world"); prints 2016-12-17 (22:27:32) > hello 2016-12-17 (22:27:32) > { world: true, hello: { amount: 1, text: hello } } 2016-12-17 (22:27:33) > world (note the missing line break after displaying the object). Code JQuery 3.1.1 main.js: (function (proxied) { function displayArg(argument){ var result= ""; if(typeof argument == "object") { result += "{ "; for (i in argument) { result += i + ": "; result += (displayArg(argument[i])); result += ", " } result = result.substring(0,result.length - 2); result += " }"; return result; } else { return argument; } } console.log = function () { var result = []; for (i in arguments) { var d = new Date(); result[i] = d.getFullYear() + "-" + (d.getMonth() + 1) + "-" + d.getDate() + " (" + d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds() + ") > "; result[i] += displayArg(arguments[i]); result[i] += "\n"; } return proxied.apply(this, result); } })(console.log);
I'm not fully understanding objective but what about something along the lines of the following oversimplified override: var oldLog = console.log; console.log= function(){ var d= new Date(), dateString = // process string ..... for(var i = 0; i<arguments.length; i++){ oldLog(dateString, arguments[i]); } }
TL;DR change the iterator variables so they don't share name, or add a "var" to the loop definition to make sure they don't escape your desired scope. It turns out that the for loops from (my own) console.log and displayArg were "sharing" the value of the iterator i. This is because by not declaring the iterator variable, the scope was broader than what I needed. To clarify, look at this example: console.log({isThis:"real life"},"hello","world") The code from console.log will add a date to the beginning of result[0] and then call displayArg(arguments[0]), arguments[0] being {isThis:"real life"}. That function, will iterate over the objects properties, thus i will be assigned the value isThis. After the function returns, the value of i will not go back to 0. Instead, i will be isThis and as a consequence, the line result[i] += "\n"; translates to result[isThis] += "\n" instead of result[0] += "\n" Probably the most sensible solution was to add a var in the for declaration of the iterators. The following code works as expected: (function (proxied) { function displayArg(argument){ var result= ""; if(typeof argument == "object") { result += "{ "; for (var i in argument) { result += i + ": "; result += (displayArg(argument[i])); result += ", " } result = result.substring(0,result.length - 2); result += " }"; return result; } else { return argument; } } console.log = function () { var result = []; for (var i in arguments) { var d = new Date(); result[i] = d.getFullYear() + "-" + (d.getMonth() + 1) + "-" + d.getDate() + " (" + d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds() + ") > "; result[i] += displayArg(arguments[i]); result[i] += "\n"; } return proxied.apply(this, result); } })(console.log);
Compare all array elements in js/jquery
Here is a demo of the current code: http://mobilocloud.com/schedule/ I have one js object that contains multiple arrays, each array has two time hashes (one start time and one end time / I've got them using getTime()). I want to compare all of the arrays contained in the object to check for all of the intersections between time ranges. I've got the script working but it only compares two arrays at a time (in the end I get groups of two overlapped events). I want to get groups of all overlapped events, not only by two. Here is the actual code: function _DetectOverlapedEvents(column) { events; groups; sgroups; todeoverlap[column] = new Array(); groups[column] = new Array(); sgroups[column] = new Array(); var $curid=0; var $curevent= new Array(); if(events[column].length > 1){ $(events[column]).each(function(key, $secondevent) { //alert("Comparing : " + $curevent["name"] + " and " + $secondevent["name"] + "\n" + $curevent["starthash"] + "<" +$secondevent["endhash"] + " = " + ($curevent["starthash"] < $secondevent["endhash"]) + "\n&&\n" + $curevent["endhash"] + ">" + $secondevent["starthash"] + " = " + ($curevent["endhash"] > $secondevent["starthash"])); if($curevent.length<2) { $curevent=$secondevent; } else if(($curevent["starthash"] < $secondevent["endhash"]) && ($curevent["endhash"] > $secondevent["starthash"])) { //alert("added " + $curevent["name"] + " and " + $secondevent["name"]); toextend = {left: $curevent, right: $secondevent}; groups[column].push(toextend); sgroups[column].push($curevent, $secondevent); //console.log("groups: " + JSON.stringify(groups[column])); $curid++; } $curevent = $secondevent; }); } //console.log(JSON.stringify(groups)); }
Displaying tweets in my website using my timezone
I am able to display my tweets in my website using the JavaScript below. window.onload = function() { var siteName = 'xyz'; $.getJSON( 'http://search.twitter.com/search.json?callback=?&rpp=20&q=from:' + siteName, function(data) { $.each(data, function(i, tweets) { for (var num = 0, len = tweets.length; num < len; num++) { if (tweets[num].text !== undefined) { $('ul#tweets').append('<li><b>' + tweets[num].created_at.substring(0, 16) + ':</b> ' + tweets[num].text + '</li>'); } } }); } ); }; This displays the tweets in US time. Is it possible to show the tweets in NZ time.
I found an easy solution to my problem. Just creating a new Date object (var tim = new Date(tweets[num].created_at)) did the trick. Here is the code which give shows date and time of tweets in my timezone. window.onload = function() { var siteName = 'xyz'; $.getJSON( 'http://search.twitter.com/search.json?callback=?&rpp=20&q=from:' + siteName, function(data) { $.each(data, function(i, tweets) { for (var num = 0, len = tweets.length; num < len; num++) { if (tweets[num].text !== undefined) { var tim = new Date(tweets[num].created_at); $('ul#tweets').append('<li><b>' + tim.toString().substring(0, 24) + ':</b> ' + tweets[num].text + '</li>'); } } }); } ); }; I think, the var tim = new Data(tweets[num].created_at) constructor is taking the date from tweets[num].created_at and converting it to local timezone (my machine time) and constructing a new object tim. So the new object tim has local time. Can anyone please point me to the documentation of the Date(dateString) constructor.
Yes. You can change the timezone. The following js code snippet was found from Twitter's web. function changetimezone(time_value, tz){ if(!tz){ tz = 0; } var values = time_value.split(" "); time_value = values[1] + " " + values[2] + ", " + values[5] + " " + values[3]; var t = parseInt(Date.parse(time_value))/1000; return t + tz * 60; } So simply parse changetimezone with created_at and your relative timezone. e.g. changetimezone(tweets[num].created_at,12); +1200hrs is New Zealand's timezone. As for what twitter returns, it's actually not US time. It's GMT+0 (London time). So you can safely put 12hrs instead of 20.