2

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

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

我曾尝试var myJsonString = JSON.stringify(JSONData);使用https://github.com/douglascrockford/JSON-js但这只是抛出错误。我怀疑是因为我的变量的起始格式错误。我曾尝试将提要称为:$.getJSON(url);并创建一个function concant1()to do the 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();
        }
}
4

1 回答 1

2

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

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

不要concat$.getJSON. 正如我上面提到的,这将为您提供 XMLHttpRequest 对象,它比您感兴趣的数据要多得多。然而,关键的是,此时尚未发出请求并且数据尚不可用。

相反,在 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);
    });
});

你马上就会注意到你从谷歌得到的原始数据和雅虎管道转换提供的数据之间仍然存在一些差异。值得注意的是,他们提供的许多值已经从对象转换为文本。例如,谷歌给我们这个:

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"

当您的雅虎转换返回的数据更像这样:

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/ 如果你想要更具体的东西,请告诉我:-)

于 2012-11-28T21:56:10.890 回答