在javascript中将多个Google日历供稿合并为一个JSON对象

时间:2012-11-28 19:58:17

标签: javascript json google-calendar-api

我正在尝试从多个Google日历中引入JSON供稿,以便我可以对即将发生的事件进行排序,并在“即将发生的事件”列表中显示下一个X号码。

我有这个与雅虎合作!管道,但我想摆脱使用第三方聚合。我认为我很接近,但我无法正确创建JSON对象。我将数据放入数组但不是JSON格式,所以我无法操纵它。

我使用https://github.com/douglascrockford/JSON-js尝试var myJsonString = JSON.stringify(JSONData);,但这只是犯了错误。我怀疑因为我的变量是错误的起始格式。我尝试过调用像$.getJSON(url);这样的Feed并创建一个function concant1()来执行JSONData=JSONData.concat(data);,但它不会触发,我认为无论如何都会产生相同的最终结果。我还尝试了几种其他方法来获得我想要的不同程度的厄运。这是我到目前为止最接近的:

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)

更新 现在有完整的工作源! :)如果有人想就如何提高代码的效率提出建议,那将非常感激。我希望其他人觉得这很有用。:

// 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();
        }
}

1 个答案:

答案 0 :(得分:2)

好的,这是需要改变的要点。

更新了小提琴:http://jsfiddle.net/ynuQ5/2/

concat的返回值不要$.getJSON。正如我上面提到的,它会为您提供XMLHttpRequest对象,这比您感兴趣的数据要多得多。但是,此时尚未提出请求并且数据尚未可用。< / p>

相反,在AJAX请求的回调中处理它。我更新了您的URL列表以使用&callback=?,初始化JSONData var以使其更像第二个屏幕截图中的结构,然后将AJAX请求的javascript更改为:

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);
    });
});

您会立即注意到您从谷歌获取的原始数据与Yahoo管道转换提供的数据之间仍存在一些差异。值得注意的是,他们提供的许多值已经从对象转换为文本。例如,谷歌给我们这个:

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"

您的yahoo转换返回的数据更像是:

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"

您可以在收到数据时更多地转换数据。或者,您可以修改显示代码以使用更复杂的原始值。

如果我能在代码或回复中清除任何内容,请告诉我。

编辑:更新了小提琴,展示了如何访问作者(显然也就是提要名称),开始时间和标题:http://jsfiddle.net/ynuQ5/8/ 如果您想要更具体的东西,请告诉我: - )