简体   繁体   中英

Google calendar event list jQuery formatting

I've been at it all day trying to find a good solution to displaying a google calendar in a list format on a website i'm developing. I came across this piece of code which works quite well except a few formatting problems. I'm not all that clued up on jQuery so I'm struggling with the formatting. I've done as much as I can from the CSS side but clearly some of it is in the script side. Maybe if someone could please help me remove the formatting in the script and have strictly css that would be great =) or another better solution =P

Thanks so much!

The format i'm after is 3 sections in different divs: date('nov 12, 09:00') event('Student Night') location('Nicci Beach')

JS:

    // Generated by CoffeeScript 1.4.0
(function() {
  var $, gCalFlow, log, methods, pad_zero, _ref;

  $ = jQuery;

  if ((typeof window !== "undefined" && window !== null) && (window._gCalFlow_debug != null) && (typeof console !== "undefined" && console !== null)) {
    log = console;
    if ((_ref = log.debug) == null) {
      log.debug = log.log;
    }
  } else {
    log = {};
    log.error = log.warn = log.log = log.info = log.debug = function() {};
  }

  pad_zero = function(num, size) {
    var i, ret, _i, _ref1;
    if (size == null) {
      size = 2;
    }
    if (10 * (size - 1) <= num) {
      return num;
    }
    ret = "";
    for (i = _i = 1, _ref1 = size - ("" + num).length; 1 <= _ref1 ? _i <= _ref1 : _i >= _ref1; i = 1 <= _ref1 ? ++_i : --_i) {
      ret = ret.concat("0");
    }
    return ret.concat(num);
  };

  gCalFlow = (function() {

    gCalFlow.prototype.target = null;

    gCalFlow.prototype.template = $("<div class=\"gCalFlow\">\n  <div class=\"gcf-header-block\">\n    <div class=\"gcf-title-block\">\n      <span class=\"gcf-title\"></span>\n    </div>\n  </div>\n  <div class=\"gcf-item-container-block\">\n    <div class=\"gcf-item-block\">\n      <div class=\"gcf-item-header-block\">\n        <div class=\"gcf-item-date-block\">\n          [<span class=\"gcf-item-daterange\"></span>]\n        </div>\n        <div class=\"gcf-item-title-block\">\n          <strong class=\"gcf-item-title\"></strong>\n        </div>\n      </div>\n      <div class=\"gcf-item-body-block\">\n        <div class=\"gcf-item-description\">\n        </div>\n        <div class=\"gcf-item-location\">\n        </div>\n      </div>\n    </div>\n  </div>\n  <div class=\"gcf-last-update-block\">\n    LastUpdate: <span class=\"gcf-last-update\"></span>\n  </div>\n</div>");

    gCalFlow.prototype.opts = {
      maxitem: 5,
      calid: null,
      mode: 'upcoming',
      feed_url: null,
      auto_scroll: false,
      scroll_interval: 10 * 1000,
      link_title: true,
      link_item_title: true,
      link_item_description: true,
      link_target: '_blank',
      item_description_in_html: false,
      callback: null,
      no_items_html: '',
      globalize_culture: (typeof navigator !== "undefined" && navigator !== null) && (navigator.browserLanguage || navigator.language || navigator.userLanguage),
      globalize_fmt_datetime: 'f',
      globalize_fmt_date: 'D',
      globalize_fmt_time: 't',
      globalize_fmt_monthday: 'M',
      date_formatter: function(d, allday_p) {
        var fmtstr;
        if ((typeof Globalize !== "undefined" && Globalize !== null) && (Globalize.format != null)) {
          if (allday_p) {
            fmtstr = this.globalize_fmt_date;
          } else {
            fmtstr = this.globalize_fmt_datetime;
          }
          return Globalize.format(d, fmtstr);
        } else {
          if (allday_p) {
            return "" + (d.getFullYear()) + "-" + (pad_zero(d.getMonth() + 1)) + "-" + (pad_zero(d.getDate()));
          } else {
            return "" + (d.getFullYear()) + "-" + (pad_zero(d.getMonth() + 1)) + "-" + (pad_zero(d.getDate())) + " " + (pad_zero(d.getHours())) + ":" + (pad_zero(d.getMinutes()));
          }
        }
      },
      daterange_formatter: function(sd, ed, allday_p) {
        var endstr, ret;
        ret = this.date_formatter(sd, allday_p);
        if (allday_p) {
          ed = new Date(ed.getTime() - 86400 * 1000);
        }
        endstr = '';
        if (sd.getDate() !== ed.getDate() || sd.getMonth() !== ed.getMonth()) {
          if ((typeof Globalize !== "undefined" && Globalize !== null) && (Globalize.format != null)) {
            endstr += Globalize.format(ed, this.globalize_fmt_monthday);
          } else {
            endstr += "" + (pad_zero(ed.getMonth() + 1)) + "-" + (pad_zero(ed.getDate()));
          }
        }
        if (!allday_p && (sd.getHours() !== ed.getHours() || sd.getMinutes() !== ed.getMinutes())) {
          if ((typeof Globalize !== "undefined" && Globalize !== null) && (Globalize.format != null)) {
            endstr += Globalize.format(ed, this.globalize_fmt_time);
          } else {
            endstr += " " + (pad_zero(ed.getHours())) + ":" + (pad_zero(ed.getMinutes()));
          }
        }
        if (endstr) {
          ret += " - " + endstr;
        }
        return ret;
      }
    };

    function gCalFlow(target, opts) {
      this.target = target;
      target.addClass('gCalFlow');
      if (target.children().size() > 0) {
        log.debug("Target node has children, use target element as template.");
        this.template = target;
      }
      this.update_opts(opts);
    }

    gCalFlow.prototype.update_opts = function(new_opts) {
      log.debug("update_opts was called");
      log.debug("old options:", this.opts);
      this.opts = $.extend({}, this.opts, new_opts);
      return log.debug("new options:", this.opts);
    };

    gCalFlow.prototype.gcal_url = function() {
      if (!this.opts.calid && !this.opts.feed_url) {
        log.error("Option calid and feed_url are missing. Abort URL generation");
        this.target.text("Error: You need to set 'calid' or 'feed_url' option.");
        throw "gCalFlow: calid and feed_url missing";
      }
      if (this.opts.feed_url) {
        return this.opts.feed_url;
      } else if (this.opts.mode === 'updates') {
        return "https://www.google.com/calendar/feeds/" + this.opts.calid + "/public/full?alt=json-in-script&max-results=" + this.opts.maxitem + "&orderby=lastmodified&sortorder=descending";
      } else {
        return "https://www.google.com/calendar/feeds/" + this.opts.calid + "/public/full?alt=json-in-script&max-results=" + this.opts.maxitem + "&orderby=starttime&futureevents=true&sortorder=ascending&singleevents=true";
      }
    };

    gCalFlow.prototype.fetch = function() {
      var success_handler,
        _this = this;
      log.debug("Starting ajax call for " + (this.gcal_url()));
      success_handler = function(data) {
        log.debug("Ajax call success. Response data:", data);
        return _this.render_data(data, _this);
      };
      return $.ajax({
        success: success_handler,
        dataType: "jsonp",
        url: this.gcal_url()
      });
    };

    gCalFlow.prototype.parse_date = function(dstr) {
      var day, hour, m, min, mon, offset, ret, sec, year;
      if (m = dstr.match(/^(\d{4})-(\d{2})-(\d{2})$/)) {
        return new Date(parseInt(m[1], 10), parseInt(m[2], 10) - 1, parseInt(m[3], 10), 0, 0, 0);
      }
      offset = (new Date()).getTimezoneOffset() * 60 * 1000;
      year = mon = day = null;
      hour = min = sec = 0;
      if (m = dstr.match(/^(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2}):(\d{2}(?:\.\d+)?)(Z|([+-])(\d{2}):(\d{2}))$/)) {
        year = parseInt(m[1], 10);
        mon = parseInt(m[2], 10);
        day = parseInt(m[3], 10);
        hour = parseInt(m[4], 10);
        min = parseInt(m[5], 10);
        sec = parseInt(m[6], 10);
        if (m[7] !== "Z") {
          offset += (m[8] === "+" ? 1 : -1) * (parseInt(m[9], 10) * 60 + parseInt(m[10], 10)) * 1000 * 60;
        }
      } else {
        log.warn("Time parse error! Unknown time pattern: " + dstr);
        return new Date(1970, 1, 1, 0, 0, 0);
      }
      log.debug("time parse (gap to local): " + offset);
      ret = new Date(new Date(year, mon - 1, day, hour, min, sec).getTime() - offset);
      log.debug("time parse: " + dstr + " -> ", ret);
      return ret;
    };

    gCalFlow.prototype.render_data = function(data) {
      var ci, desc_body_method, ed, ent, et, etf, feed, ic, it, items, link, sd, st, stf, t, titlelink, _i, _len, _ref1, _ref2;
      log.debug("start rendering for data:", data);
      feed = data.feed;
      t = this.template.clone();
      titlelink = (_ref1 = this.opts.titlelink) != null ? _ref1 : "http://www.google.com/calendar/embed?src=" + this.opts.calid;
      if (this.opts.link_title) {
        t.find('.gcf-title').html($("<a />").attr({
          target: this.opts.link_target,
          href: titlelink
        }).text(feed.title.$t));
      } else {
        t.find('.gcf-title').text(feed.title.$t);
      }
      t.find('.gcf-link').attr({
        target: this.opts.link_target,
        href: titlelink
      });
      t.find('.gcf-last-update').html(this.opts.date_formatter(this.parse_date(feed.updated.$t)));
      it = t.find('.gcf-item-block');
      it.detach();
      it = $(it[0]);
      log.debug("item block template:", it);
      items = $();
      log.debug("render entries:", feed.entry);
      if (this.opts.item_description_as_html) {
        desc_body_method = 'html';
      } else {
        desc_body_method = 'text';
      }
      if ((feed.entry != null) && feed.entry.length > 0) {
        _ref2 = feed.entry.slice(0, +this.opts.maxitem + 1 || 9e9);
        for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
          ent = _ref2[_i];
          log.debug("formatting entry:", ent);
          ci = it.clone();
          if (ent.gd$when) {
            st = ent.gd$when[0].startTime;
            sd = this.parse_date(st);
            stf = this.opts.date_formatter(sd, st.indexOf(':') < 0);
            ci.find('.gcf-item-date').html(stf);
            ci.find('.gcf-item-start-date').html(stf);
            et = ent.gd$when[0].endTime;
            ed = this.parse_date(et);
            etf = this.opts.date_formatter(ed, et.indexOf(':') < 0);
            ci.find('.gcf-item-end-date').html(etf);
            ci.find('.gcf-item-daterange').html(this.opts.daterange_formatter(sd, ed, st.indexOf(':') < 0));
          }
          ci.find('.gcf-item-update-date').html(this.opts.date_formatter(this.parse_date(ent.updated.$t), false));
          link = $('<a />').attr({
            target: this.opts.link_target,
            href: ent.link[0].href
          });
          if (this.opts.link_item_title) {
            ci.find('.gcf-item-title').html(link.clone().text(ent.title.$t));
          } else {
            ci.find('.gcf-item-title').text(ent.title.$t);
          }
          if (this.opts.link_item_description) {
            ci.find('.gcf-item-description').html(link.clone()[desc_body_method](ent.content.$t));
          } else {
            ci.find('.gcf-item-description')[desc_body_method](ent.content.$t);
          }
          ci.find('.gcf-item-location').text(ent.gd$where[0].valueString);
          ci.find('.gcf-item-link').attr({
            href: ent.link[0].href
          });
          log.debug("formatted item entry:", ci[0]);
          items.push(ci[0]);
        }
      } else {
        items = $('<div class=".gcf-no-items"></div>').html(this.opts.no_items_html);
      }
      log.debug("formatted item entry array:", items);
      ic = t.find('.gcf-item-container-block');
      log.debug("item container element:", ic);
      ic.html(items);
      this.target.html(t.html());
      this.bind_scroll();
      if (this.opts.callback) {
        return this.opts.callback.apply(this.target);
      }
    };

    gCalFlow.prototype.bind_scroll = function() {
      var scroll_children, scroll_container, scroll_timer, scroller, state;
      scroll_container = this.target.find('.gcf-item-container-block');
      scroll_children = scroll_container.find(".gcf-item-block");
      log.debug("scroll container:", scroll_container);
      if (!this.opts.auto_scroll || scroll_container.size() < 1 || scroll_children.size() < 2) {
        return;
      }
      state = {
        idx: 0
      };
      scroller = function() {
        var scroll_to;
        log.debug("current scroll position:", scroll_container.scrollTop());
        log.debug("scroll capacity:", scroll_container[0].scrollHeight - scroll_container[0].clientHeight);
        if (typeof scroll_children[state.idx] === 'undefined' || scroll_container.scrollTop() >= scroll_container[0].scrollHeight - scroll_container[0].clientHeight) {
          log.debug("scroll to top");
          state.idx = 0;
          return scroll_container.animate({
            scrollTop: scroll_children[0].offsetTop
          });
        } else {
          scroll_to = scroll_children[state.idx].offsetTop;
          log.debug("scroll to " + scroll_to + "px");
          scroll_container.animate({
            scrollTop: scroll_to
          });
          return state.idx += 1;
        }
      };
      return scroll_timer = setInterval(scroller, this.opts.scroll_interval);
    };

    return gCalFlow;

  })();

  methods = {
    init: function(opts) {
      var data;
      if (opts == null) {
        opts = {};
      }
      data = this.data('gCalFlow');
      if (!data) {
        return this.data('gCalFlow', {
          target: this,
          obj: new gCalFlow(this, opts)
        });
      }
    },
    destroy: function() {
      var data;
      data = this.data('gCalFlow');
      data.obj.target = null;
      $(window).unbind('.gCalFlow');
      data.gCalFlow.remove();
      return this.removeData('gCalFlow');
    },
    render: function() {
      if ((typeof Globalize !== "undefined" && Globalize !== null) && (Globalize.culture != null)) {
        Globalize.culture(this.data('gCalFlow').obj.opts.globalize_culture);
      }
      return this.data('gCalFlow').obj.fetch();
    }
  };

  $.fn.gCalFlow = function(method) {
    var orig_args;
    orig_args = arguments;
    if (typeof method === 'object' || !method) {
      return this.each(function() {
        methods.init.apply($(this), orig_args);
        return methods.render.apply($(this), orig_args);
      });
    } else if (methods[method]) {
      return this.each(function() {
        return methods[method].apply($(this), Array.prototype.slice.call(orig_args, 1));
      });
    } else if (method === 'version') {
      return "1.2.5";
    } else {
      return $.error("Method " + method + " does not exist on jQuery.gCalFlow");
    }
  };

}).call(this);

HTML:

<div id="gcf-custom-template">
                      <div class="gcf-item-container-block">
                        <div class="gcf-item-block">
                          <div class="gcf-item-header-block">
                                <div class="gcf-item-title-block">
                                  <div style="float: left; width 250px;"><a class="gcf-item-link"><span class="gcf-item-daterange">2012-02-01 09:00</span>:</a></div>
                                  <div style="float: left; width 250px;"><a class="gcf-item-location">1-877-346-9707 w 55586#</a></div>
                                  <div style="float: left; width 250px;"><strong><a class="gcf-item-title">Item Title of Your event</a></strong></div>
                                </div>
                          </div>
                        </div>
                      </div>
                     </div>

Script Call:

<script type="text/javascript">
      var $ = jQuery;
      $(function() {
        $('#gcf-custom-template').gCalFlow({
          calid: '4t0m1c.w07f@gmail.com',
          maxitem: 50,
          mode: 'updates',
          date_formatter: function(d, allday_p) { return (d.getMonth()+1) + "/" + d.getDate() + "/" + d.getYear().toString().substr(-2) }
        });
      });
    </script>

Here is my solution to a similar problem, using moment.js for date formatting, markupjs for templating, and jQuery for general making life easier.

// a markup.js pipe which calls on moment.js for formatting
Mark.pipes.moment = function (date, format) {
    return moment(new Date(date)).format(format);
};

// a markup.js pipe that tests if two dates are in the same month (difference between "1st-2nd december" and "30 november - 2 december")
Mark.pipes.diffmonth = function (date1, date2) {
  moment1 = moment(new Date(date1));
  moment2 = moment(new Date(date2));
  var ret= moment1.month()!=moment2.month();
  return ret;
};

// a markup.js pipe to filter an array
Mark.pipes.sift = function (arr, prop, val) {
  return $.grep(arr,function(item) {
    return item[prop] == val;
  });
};

$(document).ready(loadCalendarData);

// this is a google calendar public full json feed (to have complete date and location information) 
calendarURL = "http://www.google.com/calendar/feeds/6vv7tct80gv5tblahm5sg0vsos@group.calendar.google.com/public/full?alt=json-in-script&orderby=starttime&singleevents=true&sortorder=ascending&futureevents=true&callback=?";

function loadCalendarData() {
  $.getJSON( calendarURL, applyTemplate);
}

function applyTemplate(cal_data) {

  // format dates in french
  moment.lang("fr");

  // take cal_data, a google calendar json full feed. and extract VCALENDAR fields. Also extract a type field that distinguishes single day events from multiple day events.
  var events = $.map(cal_data["feed"]["entry"], function (event) {
    var url= $.grep(event["link"], function(link) {
      return link["rel"]=="related";
    });
    return {
      "summary": event["title"]["$t"],
      "dtstart": event["gd$when"][0]["startTime"],
      "dtend": event["gd$when"][0]["endTime"],
      "url": url[0]?url[0]["href"]:"",
      "location": event["gd$where"][0]["valueString"],
      "type": (moment.duration(new Date(event["gd$when"][0]["endTime"])-new Date(event["gd$when"][0]["startTime"])).as("hours")<18)?"single":"multi"
    };

  });

  // summary with url link if exists
  Mark.includes.linked_summary = "{{if url}}<a href='{{url}}'>{{/if}}{{summary}}{{if url}}</a>{{/if}}";
  // location in brackets if exists
  Mark.includes.optional_location = "{{if location}}&nbsp;({{location}}){{/if}}"

  // separate list of evenings and multiple day/weeked events
  var template = 
    "Les soir&eacute;es &agrave; venir :<ul>{{events|sift>type>single}}"+ 
    "<li>{{dtstart|moment>dddd|capcase}} {{dtstart|moment>D/M}}: {{linked_summary}}{{optional_location}}</li>"+
    "{{/events}}</ul>"+
    "<br>"+
    "Les stages et weekends &agrave; venir (2013/2014):<ul>{{events|sift>type>multi}}"+
    "<li>{{dtstart|moment>D}}{{if dtstart|diffmonth>`dtend`}}{{dtstart|moment>/M}}{{/if}}-{{dtend|moment>D/M}}: {{linked_summary}}{{optional_location}}</li>"+
    "{{/events}}</ul>";

  $("#web").html(Mark.up(template, {"events":events}));
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM