Giter Site home page Giter Site logo

kylestetz / clndr Goto Github PK

View Code? Open in Web Editor NEW
2.8K 129.0 450.0 1.1 MB

:calendar: a jQuery calendar plugin that uses HTML templates

Home Page: http://kylestetz.github.io/CLNDR/

License: MIT License

JavaScript 86.32% HTML 13.68%
calendar jquery-plugin

clndr's Introduction

CLNDR.js

CLNDR is a jQuery calendar plugin. It was created -- you've heard this before -- out of frustration with the lack of truly dynamic front-end calendar plugins out there.

See a demo: kylestetz.github.io/CLNDR/


Download

Returning to grab a new version? Have a look at the CHANGELOG.md file.

If you'd like to run some tests in a particular browser or environment, tests/test.html contains a list of basic functionality tests. When contributing, please run these (and add to them when appropriate) before submitting a pull request or issue!

Dependencies

jQuery and Moment.js are depended upon. By default CLNDR tries to use Underscore.js's _.template() function, however if you specify a custom rendering function (see documentation below) Underscore will not be used at all.

Because their APIs are the same, Lo-Dash's _.template() function will work as well! Just include Lo-Dash instead of Underscore.

Using NPM

You can install CLNDR via NPM:

npm install clndr

Underscore is not installed by default. This allows you to use whichever templating engine you want to. If you want to use the default template option with Underscore, just install it as a dependency of your project: npm install underscore or npm install lodash.

Using Bower

You can install CLNDR via Bower:

bower install clndr

Underscore is not installed by default. This allows you to use whichever templating engine you want to. If you want to use the default template option with Underscore, just install it as a dependency of your project: bower install underscore or bower install lodash.

CLNDR Using Angular

If you want to integrate clndr into an angular.js site, get started with this directive: angular-clndr.

CLNDR Using Rails

If you're building a rails application you may be interested in this gem by @sedx: clndr-rails.

Introduction: You Write The Markup

There are wonderful and feature-rich calendar modules out there and they all suffer the same problem: they give you markup (and often a good heap of JS) that you have to work with and style. This leads to a lot of hacking, pushing, pulling, and annoying why-can't-it-do-what-I-want scenarios.

CLNDR doesn't generate markup (well, it has some reasonable defaults, but that's an aside). Instead, CLNDR asks you to create a template and in return it supplies your template with a great set of objects that will get you up and running in a few lines.

The 'Days' Array

Here's a typical CLNDR template. It's got a controller section and a grid section.

<div class="clndr-controls">
  <div class="clndr-previous-button">&lsaquo;</div>
  <div class="month"><%= month %></div>
  <div class="clndr-next-button">&rsaquo;</div>
</div>
<div class="clndr-grid">
  <div class="days-of-the-week">
  <% _.each(daysOfTheWeek, function (day) { %>
    <div class="header-day"><%= day %></div>
  <% }) %>
    <div class="days">
    <% _.each(days, function (day) { %>
      <div class="<%= day.classes %>"><%= day.day %></div>
    <% }) %>
    </div>
  </div>
</div>

The days array contains most of the stuff we need to make a calendar. Its structure looks like this:

{
  day: 5,
  events: [],
  classes: "day",
  date: moment("2015-12-31")
}

This makes quick work of generating a grid. days.classes contains extra classes depending on the circumstance: if a given day is today, 'today' will show up, as well as an 'event' class when an event lands on that day.

Pass In Your Events

CLNDR accepts events as an array of objects:

events = [
  {
    date: "YYYY-MM-DD or some other ISO Date format",
    and: "anything else"
  }
]

CLNDR looks through the objects in your events array for a date field unless you specify otherwise using the dateParameter option. In your template the days array will auto-magically contain these event objects in their entirety. See the examples for a demonstration of how events populate the days array.

Usage

CLNDR leans on the awesome work done in Underscore and moment. These are requirements unless you are using a different rendering engine, in which case Underscore is not a requirement). Do be sure to include them in your <head> before clndr.js. It is a jQuery plugin, so naturally you'll need that as well.

The bare minimum (CLNDR includes a default template):

$('.parent-element').clndr();

With all of the available options:

$('.parent-element').clndr({

  // The template: this could be stored in markup as a
  //   <script type="text/template"></script>
  // or pulled in as a string
  template: clndrTemplate,

  // Determines which month to start with using either a date string or a
  // moment object.
  startWithMonth: "YYYY-MM-DD" or moment(),

  // Start the week off on Sunday (0), Monday (1), etc. Sunday is the default.
  // WARNING: if you are dealing with i18n and multiple languages, you
  // probably don't want this! See the "Internationalization" section below
  // for more.
  weekOffset: 0,

  // An array of day abbreviation labels. If you have moment.js set to a
  // different language, it will guess these for you! If for some reason that
  // doesn't work, use this...
  // WARNING: if you are dealing with i18n and multiple languages, you
  // probably don't want this! See the "Internationalization" section below
  // for more.
  daysOfTheWeek: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],

  // Optional callback function that formats the day in the header. If none
  // supplied, defaults to moment's `dd` and truncates to one character.
  // The callback is passed a moment object representing the day, and a string
  // is to be returned.
  formatWeekdayHeader: function (day) {
    return day.format('dd').charAt(0);
  },

  // The target classnames that CLNDR will look for to bind events.
  // these are the defaults.
  targets: {
    day: 'day',
    empty: 'empty',
    nextButton: 'clndr-next-button',
    todayButton: 'clndr-today-button',
    previousButton: 'clndr-previous-button',
    nextYearButton: 'clndr-next-year-button',
    previousYearButton: 'clndr-previous-year-button',
  },

  // Custom classes to avoid styling issues. pass in only the classnames that
  // you wish to override. These are the defaults.
  classes: {
    past: "past",
    today: "today",
    event: "event",
    selected: "selected",
    inactive: "inactive",
    lastMonth: "last-month",
    nextMonth: "next-month",
    adjacentMonth: "adjacent-month",
  },

  // Click callbacks! The keyword 'this' is set to the clndr instance in all
  // callbacks.
  clickEvents: {
    // Fired whenever a calendar box is clicked. Returns a 'target' object
    // containing the DOM element, any events, and the date as a moment.js
    // object.
    click: function (target) {...},

    // Fired when a user goes to the current month and year. Returns a
    // moment.js object set to the correct month.
    today: function (month) {...},

    // Fired when a user goes forward a month. Returns a moment.js object
    // set to the correct month.
    nextMonth: function (month) {...},

    // Fired when a user goes back a month. Returns a moment.js object set
    // to the correct month.
    previousMonth: function (month) {...},

    // Fires any time the month changes as a result of a click action.
    // Returns a moment.js object set to the correct month.
    onMonthChange: function (month) {...},

    // Fired when the next year button is clicked. Returns a moment.js
    // object set to the correct month and year.
    nextYear: function (month) {...},

    // Fired when the previous year button is clicked. Returns a moment.js
    // object set to the correct month and year.
    previousYear: function (month) {...},

    // Fires any time the year changes as a result of a click action. If
    // onMonthChange is also set, it is fired BEFORE onYearChange. Returns
    // a moment.js object set to the correct month and year.
    onYearChange: function (month) {...},

    // Fired when a user goes forward a period. Returns moment.js objects
    // for the updated start and end date.
    nextInterval: function (start, end) {...},

    // Fired when a user goes back an interval. Returns moment.js objects for
    // the updated start and end date.
    previousInterval: function (start, end) {...},

    // Fired whenever the time period changes as configured in lengthOfTime.
    // Returns moment.js objects for the updated start and end date.
    onIntervalChange: function (start, end) {...}
  },

  // Use the 'touchstart' event instead of 'click'
  useTouchEvents: false,

  // This is called only once after clndr has been initialized and rendered.
  // use this to bind custom event handlers that don't need to be re-attached
  // every time the month changes (most event handlers fall in this category).
  // Hint: this.element refers to the parent element that holds the clndr,
  // and is a great place to attach handlers that don't get tossed out every
  // time the clndr is re-rendered.
  ready: function () { },

  // A callback when the calendar is done rendering. This is a good place
  // to bind custom event handlers (also see the 'ready' option above).
  doneRendering: function () {...},

  // An array of event objects
  events: [
    {
      title: 'This is an event',
      date: '2000-08-20'
    },
    ...
  ],

  // If you're supplying an events array, dateParameter points to the field
  // in your event object containing a date string. It's set to 'date' by
  // default.
  dateParameter: 'date',

  // CLNDR can accept events lasting more than one day! just pass in the
  // multiDayEvents option and specify what the start and end fields are
  // called within your event objects. See the example file for a working
  // instance of this.
  multiDayEvents: {
    endDate: 'endDate',
    startDate: 'startDate',
    // If you also have single day events with a different date field,
    // use the singleDay property and point it to the date field.
    singleDay: 'date'
  },

  // Show the dates of days in months adjacent to the current month. Defaults
  // to true.
  showAdjacentMonths: true,

  // When days from adjacent months are clicked, switch the current month.
  // fires nextMonth/previousMonth/onMonthChange click callbacks. defaults to
  // false.
  adjacentDaysChangeMonth: false,

  // Always make the calendar six rows tall (42 days) so that every month has
  // a consistent height. defaults to 'false'.
  forceSixRows: null,

  // Set this to true, if you want the plugin to track the last clicked day.
  // If trackSelectedDate is true, "selected" class will always be applied
  // only to the most recently clicked date; otherwise - selectedDate will
  // not change.
  trackSelectedDate: false,

  // Set this, if you want a date to be "selected" (see classes.selected)
  // after plugin init. Defualts to null, no initially selected date.
  selectedDate: null,

  // Set this to true if you don't want `inactive` dates to be selectable.
  // This will only matter if you are using the `constraints` option.
  ignoreInactiveDaysInSelection: null,

  // CLNDR can render in any time interval!
  // You can specify if you want to render one or more months, or one ore more
  // days in the calendar, as well as the paging interval whenever forward or
  // back is triggered. If both months and days are null, CLNDR will default
  // to the standard monthly view.
  lengthOfTime: {
    // Set to an integer if you want to render one or more months, otherwise
    // leave this null
    months: null,

    // Set to an integer if you want to render one or more days, otherwise
    // leave this null. Setting this to 14 would render a 2-week calendar.
    days: null,

    // This is the amount of months or days that will move forward/back when
    // paging the calendar. With days=14 and interval=7, you would have a
    // 2-week calendar that pages forward and backward 1 week at a time.
    interval: 1
  },

  // Any other data variables you want access to in your template. This gets
  // passed into the template function.
  extras: {},

  // If you want to use a different templating language, here's your ticket.
  // Precompile your template (before you call clndr), pass the data from the
  // render function into your template, and return the result. The result
  // must be a string containing valid markup. The keyword 'this' is set to
  // the clndr instance in case you need access to any other properties.
  // More under 'Template Rendering Engine' below.
  render: function (data) {
    return '<div class="html data as a string"></div>';
  },

  // If you want to prevent the user from navigating the calendar outside
  // of a certain date range (e.g. if you are making a datepicker), specify
  // either the startDate, endDate, or both in the constraints option. You
  // can change these while the calendar is on the page... See documentation
  // below for more on this!
  constraints: {
    startDate: '2017-12-22',
    endDate: '2018-01-09'
  },

  // Optionally, you can pass a Moment instance to use instead of the CLNDR settings. 
  // If you use moment you shouldn't use weekOffset and daysOfTheWeek
  // See https://github.com/kylestetz/CLNDR#internationalization for more information
  moment: null
});

All of the things you have access to in your template:

// An array of day-of-the-week abbreviations, shifted as requested using the
// weekOffset parameter.
daysOfTheWeek: ['S', 'M', 'T', etc...]

// The number of 7-block calendar rows, in the event that you want to do some
// looping with it
numberOfRows: 5

// The days array, documented in more detail above
days: [{ day, classes, id, events, date }]

// The month name- don't forget that you can do things like
// month.substring(0, 1) and month.toLowerCase() in your template
month: "May"

// The year that the calendar is currently focused on
year: "2013"

// All of the events happening this month. This will be empty of the
// lengthOfTime config option is set.
eventsThisMonth: []
// All of the events happening last month. This is only set if
// showAdjacementMonths is true.
eventsLastMonth: []
// All of the events happening next month. This is only set if
// showAdjacementMonths is true.
eventsNextMonth: []

// If you specified a custom lengthOfTime, you will have these instead.
intervalEnd: (moment object)
intervalStart: (moment object)
eventsThisInterval: []

// Anything you passed into the 'extras' property when creating the clndr
extras: {}

Multi-day Events

CLNDR accepts events lasting more than one day. You just need to tell it how to access the start and end dates of your events:

var lotsOfEvents = [
  {
    end: '2013-11-08',
    start: '2013-11-04',
    title: 'Monday to Friday Event'
  }, {
    end: '2013-11-20',
    start: '2013-11-15',
    title: 'Another Long Event'
  }
];

$('#calendar').clndr({
  events: lotsOfEvents,
  multiDayEvents: {
    endDate: 'end',
    startDate: 'start'
  }
});

When looping through days in my template, 'Monday to Friday Event' will be passed to every single day between the start and end date. See index.html in the example folder for a demo of this feature.

Mixing Multi- and Single-day Events

If you also have single-day events mixed in with different date fields, as of clndr v1.2.7 you can specify a third property of multiDayEvents called singleDay that refers to the date field for a single-day event.

var lotsOfMixedEvents = [
  {
    end: '2015-11-08',
    start: '2015-11-04',
    title: 'Monday to Friday Event'
  }, {
    end: '2015-11-20',
    start: '2015-11-15',
    title: 'Another Long Event'
  }, {
    title: 'Birthday',
    date: '2015-07-16'
  }
];

$('#calendar').clndr({
  events: lotsOfEvents,
  multiDayEvents: {
    endDate: 'end',
    singleDay: 'date',
    startDate: 'start'
  }
});

Custom Classes

The classes that get added to a day object automatically can be customized to avoid styling conflicts. The classes option accepts today, event, past, lastMonth, nextMonth, adjacentMonth, and inactive. Pass in only the classnames you wish to override and the rest will be set to their defaults.

In this example we create a my- namespace for all of the classes:

clndr.customClasses = $('#custom-classes').clndr({
  classes: {
    past: "my-past",
    today: "my-today",
    event: "my-event",
    inactive: "my-inactive",
    lastMonth: "my-last-month",
    nextMonth: "my-next-month",
    adjacentMonth: "my-adjacent-month"
  }
});

To configure the day, empty, and next/previous/today/etc. button classes, use the targets option documented in the usage section.

Constraints & Datepickers

If you are making a datepicker or you'd just like to prevent users from nexting all the way to 2034 in your calendar, you can pass a constraints option with startDate, endDate, or both specified:

$('#calendar').clndr({
  constraints: {
    endDate: '2015-07-16',
    startDate: '2015-05-06'
  }
});

Now your calendar's next and previous buttons will only work within this date range. When they become disabled they will have the class 'inactive', which you can use to gray them out or add gif flames or whatever.

The days in your grid that are outside of the range will also have the inactive class. This means that you will want to add a click callback and check for whether or not a day has the class inactive. It will look like this:

$('#calendar').clndr({
  constraints: {
    endDate: '2015-07-16',
    startDate: '2015-05-06'
  },
  clickEvents: {
    click: function (target) {
      if (!$(target.element).hasClass('inactive')) {
        console.log('You picked a valid date!');
      } else {
        console.log('That date is outside of the range.');
      }
    }
  }
});

The constraints can be updated at any time via clndr.options.constraints. If you make a change, call render() afterwards so that clndr can update your interface with the appropriate classes.

myCalendar.options.constraints.startDate = '1999-12-31';
myCalendar.render();

Make sure the startDate comes before the endDate!

Returning the Instance / Public API

It's possible to save the clndr object in order to call it from JS later. There are functions to increment or set the month or year. You can also provide a new events array.

// Create a CLNDR and save the instance as myCalendar
var myCalendar = $('#myCalendar').clndr();

// Go to the next month
myCalendar.forward();

// Go to the previous month
myCalendar.back();

// Set the month using a number from 0-11 or a month name
myCalendar.setMonth(0);
myCalendar.setMonth('February');

// Go to the next year
myCalendar.nextYear();

// Go to the previous year
myCalendar.previousYear();

// Set the year
myCalendar.setYear(1997);

// Go to today:
myCalendar.today();

// Overwrite the extras. Note that this triggers a re-render of the calendar.
myCalendar.setExtras(newExtras);

// Change the events. Note that this triggers a re-render of the calendar.
myCalendar.setEvents(newEventsArray);

// Add events. Note that this triggers a re-render of the calendar.
myCalendar.addEvents(additionalEventsArray);

// Remove events.  All events for which the passed in function returns true will
// be removed from the calendar. Note that this triggers a re-render of the
// calendar.
myCalendar.removeEvents(function (event) {
  return event.id === idToRemove;
});

// Destroy the clndr instance. This will empty the DOM node containing the
// calendar.
myCalendar.destroy();

If you are taking advantage of the onMonthChange and onYearChange callbacks, you might want them to fire whenver you call setMonth, setYear, forward, back, etc. Just pass in an object as an argument with withCallbacks: true like this:

// Month will be set to February and then onMonthChange will be fired.
myCalendar.setMonth("February", { withCallbacks: true });

// Month will increment and onMonthChange, and possibly onYearChange, will be
// fired.
myCalendar.next({ withCallbacks: true });

Template Requirements

CLNDR is structured so that you don't really need anything in your template.

<% _.each(days, function (day) { %>
<div class='<%= day.classes %>'><%= day.day %></div>
<% }); %>

Currently CLNDR sets the class on a day to 'calendar-day-2013-05-30' and uses it to determine the date when a user clicks on it. Thus, click events will only work if days.classes is included in your day element's class attribute as seen above.

Configuration

Template Rendering Engine

You can pass in a render function as an option, for example:

var precompiledTemplate = myRenderingEngine.template($('#my-template').html());

$('#my-calendar').clndr({
  render: function (data) {
    return precompiledTemplate(data);
  }
});

Where the function must return the HTML result of the rendering operation. In this case you would precompile your template elsewhere in your code, since CLNDR only cares about your template if it's going to use Underscore.

If you are using your own render method, Underscore is NOT a dependency of this plugin.

CLNDR has been tested successfully with doT.js, Hogan.js, Handlebars.js, Mustache.js, and Knockout.js. Please get in touch if you have success with other languages and they will be documented here.

Here's an example using doT.js...

The markup:

<script id="dot-template" type="text/template">
  <div class="clndr-controls">
    <div class="clndr-previous-button">&lsaquo;</div>
    <div class="month">{{= it.month }}</div>
    <div class="clndr-next-button">&rsaquo;</div>
  </div>
  <div class="clndr-grid">
    <div class="days-of-the-week">
    {{~it.daysOfTheWeek :day:index}}
      <div class="header-day">{{= day }}</div>
    {{~}}
      <div class="days">
      {{~it.days :day:index}}
        <div class="{{= day.classes }}">{{= day.day }}</div>
      {{~}}
      </div>
    </div>
  </div>
</script>

The Javascript:

var clndrTemplate = doT.template($('#dot-template').html());

$('#calendar').clndr({
  render: function (data) {
    return clndrTemplate(data);
  }
});

Here's an example using Mustache.js...

The markup:

<script type="x-tmpl-mustache" id="calendar-tmpl">
  <div class="controls">
    <span class="clndr-previous-button">prev</span>
    <span class="month">{{month}}</span>
    <span class="year">{{year}}</span>
    <span class="clndr-next-button">next</span>
  </div>
  <div class="days-container">
    <div class="days">
      <div class="headers">
        {{#daysOfTheWeek}}
          <div class="day-header">{{.}}</div>
        {{/daysOfTheWeek}}
      </div>
      {{#days}}
        <div class="{{classes}}" id="{{id}}">{{day}}</div>
      {{/days}}
    </div>
  </div>
</script>

The Javascript:

$('#calendar').clndr({
  render: function (data) {
    return Mustache.render($('#calendar-tmpl').html(), data);
  },
});

Internationalization

CLNDR has support for internationalization insofar as Moment.js supports it. By configuring your Moment.js instance to a different language, which you can read more about here: i18n in Moment.js, you are configuring CLNDR as well.

If you would prefer to pass in a pre-configured instance of moment, you can do this by passing it in as the moment config option when initializing CLNDR:

// To change clndr to German use moment.local('de')
moment.locale('de');

// Make sure that your locale is Working correctly
console.log(moment().calendar())
// Returns "heute um 18:43 Uhr"

$('#calendar').clndr({
  // Pass the moment instance to use your language settings
  moment: moment
});

If you are using a moment.js language configuration in which weeks begin on a Monday (e.g. French), CLNDR will detect this automatically and there is no need to provide a weekOffset or a daysOfTheWeek array. If you want to reverse this behavior, there is a field in each moment.js language config file called dow which you can set to your liking.

The day of the week abbreviations are created automatically using moment.js's current language setting, however if this does not suit your needs you should override them using the daysOfTheWeek option. Make sure the array you provide begins on the same day of the week as your current language setting. Warning: using daysOfTheWeek and weekOffset in conjunction with different language settings is not recommended and may cause you headaches.

Underscore Template Delimiters

If you're not a fan of <% %> and <%= %> style delimiters you can provide Underscore.js with alternatives in the form of regular expressions. There are three delimiters...

interpolate, which outputs a string (this is <%= %> by default)

escape, for escaping HTML (this is <%- %> by default)

evaluate, for evaluating javascript (this is <% %> by default)

If you're more comfortable with Jinja2/Twig/Nunjucks style delimiters, simply call this before you instantiate your clndr:

// Switch to Jinja2/Twig/Nunjucks-style delimiters
_.templateSettings = {
  escape: /\{\{\-(.+?)\}\}/g,
  evaluate: /\{\%(.+?)\%\}/g,
  interpolate: /\{\{(.+?)\}\}/g,
};

Internet Explorer Issues

If you're planning on supporting IE8 and below, you'll have to be careful about version dependencies. You'll need the jQuery 1.10.x branch for IE support, and if you're taking advantage of the constraints feature you'll need to use a version of moment.js <=2.1.0 or >=2.5.1.

Submitting Issues

GitHub issues and support tickets are to be submitted only for bugs. We sadly don't have the time or manpower to answer implementation questions, debug your application code, or anything that isn't directly related to a CLNDR bug :D There are many wonderful places to seek help, like Stack Overflow.

clndr's People

Contributors

ahrengot avatar alexnsolo avatar bhoodream avatar cabralrodrigo avatar cwackerman avatar dependabot[bot] avatar dmeremyanin avatar dzoeteman avatar eirikurn avatar elidupuis avatar foaly-nr1 avatar greatwizard avatar hellomanoj avatar jaakon avatar jonathanguo avatar keioka avatar kkirsche avatar kruppel avatar kylestetz avatar lukefrake avatar macsdickinson avatar madand avatar mcmathews avatar mikegioia avatar padam87 avatar palodelincak avatar paulfalgout avatar pephers avatar phuibonhoa avatar ymslavov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

clndr's Issues

conflict with ejs

Hi
I am using ejs as backend template engine, the clndr default template delimiters is conflict wth ejs, do you have any solution?

[Question] Multiple Calendars

Hi Kyle!

I think it's a simple question.
Instead of having the navigation buttons, to see the next and previous months, is there a way to do something like this > http://i.imgur.com/qNQbJ8y.png, without messing the code?

I'm using the basic code that you show in the exemple.
When i say "messing the code" i mean do something like this: http://pastebin.com/SX62GPq6

And each one will have a an date with event.

Sorry for my bad english, if you don't understand my question, i'll to explain again :)

Constraints seems doesn't work in IE8

When I try the below setup:

    constraints: {
      startDate: '2013-01-01',
      endDate: '2013-12-31'
    } 

Work great for Chrome, but it seems be ignored by IE8.

eventsThisDay in addition to eventsThisMonth

Hi and a very big thanks for this calendar, it's awesome :) !

For my website, I've rebuild the calendar there http://kylestetz.github.io/CLNDR/#mini-clndr . So when I click on a date, I see the list of the events for the current month.

In this list, I would like to display only the events that are linked to the clicked date, not to the whole month. I think it's a more logical behavior since the visitor click on a date, not on a month.

Maybe could you add a eventsThisDay for the template or tell me how to achieve that ?

Thanks a lot,
Cรฉdric

nextDay / previous Day

Would it be possible to add a function to navigate inside a Day to the next / previous dayยดs events? how to do this at best?

how to select all the dates in a month and add background image to it?

I'm trying to add background image to all the dates in that particular month which is shown. How can this be achieved?

I tried with this, but it will apply to the whole days class, which is obviously not what i want. Any help is appreciated.

$(".day").each(function(){
    $(this).children().css("background","url(http://jasonlefkowitz.net/wp-content/uploads/2013/07/Cats.jpg)");
});

Issue with Internationalization

Hi,

I use CLNDR for the first time, thanks for this work! But I have an issue with internationalization, I build a website in 9 differents languages.

So, in English, it's ok, but in other language, when the week doesn't start with Sunday, it's not good. I use Moment.js (2.2.1), with one JS file per language.

(For example, I'm using this file for French : https://github.com/moment/moment/blob/develop/lang/fr.js )

If I don't set the option weekOffset to CLNDR,
capture decran 2013-10-15 a 18 03 59

The head is good, and start by "L" (Monday) so it's OK, but the days below are not ok, today we are the 15th, "M" (Tuesday), it should be the second column, not the third.

And, if I set the weekOffset to 1 for CLNDR, as you say in the doc
capture decran 2013-10-15 a 18 07 17

the head is not ok, and start by Tuesday, but the days below are ok, and start by monday...

The array weekdaysMin in the file https://github.com/moment/moment/blob/develop/lang/fr.js start by Sunday as you say in the doc, but the variable dow (same JS file) tell the first day is monday, so I think it's modify the array in moment.js. My stuff work if i set dow to 0 in all my language file starting by Monday, but it's not very handy if we need to change every moment lang JS file every time...)

(For information, i'm using the default template you're providing)

(Sorry for my English, hope you'll understand me ;) )

Display Clicked Date Only

When clicking a date in the full month view, is it possible to have the plugin only display events for the clicked date instead of showing the entire month?

Should be a Table

I understand this sounds like unforgivable blasphemy but a calendar is actually a table. Yes, yes, I know all the "don't use tables for page layout" stuff. Believe me, I know that. But I'm not talking about page layout here. I'm talking about presenting tabular data and a calendar is tabular data: http://codepen.io/WebDevCA/pen/tsHpw

Update 1.07 (IE8 fix) breaks eventsNextMonth usage for handlebars

I am using Handlebars as a template language. Today I wanted to update my clndr.js, as I was still using the 1.0.4 version.

After updating to version 1.0.12, the calendar broke. So I went looking for the problem and saw that my calendar broke by the IE 8 fixes (update 1.0.7).

The problem is that some functions like eventsNextMonth returned plain array before 1.0.7. After 1.0.7, the options.events are 'jQueryfied' and so return a jQuery objects. As Handlebars each helper only works with plain objects/arrays, the functions doen't work anymore.

For me I could fix this by adding jQuery's toArray() at line 67:

if (this.eventsLastMonth = [], this.eventsThisMonth = [], this.eventsNextMonth = [], this.options.events.length && (this.eventsThisMonth = $(this.options.events).filter(function() { return this._clndrDateObject.format("YYYY-MM") == currentMonth.format("YYYY-MM"); }).toArray(), this.options.showAdjacentMonths))

Could this be fixed in an upcoming version?

Months are one day behind in v1.0.13

Hey, I think latest version (v1.0.13) has a bug.
It is showing me all months starting one day behind.

Example
Reality: October 1st, 2013 is a Tuesday
CLNDR: October 1st, 2013 is a Monday

Year-view calendar ?

Hello, i don't know if this is the right place to ask such a question, but how would i go about doing a year-view calendar (while keeping support for events) ? i thought about using multiple instances of CLNDR, one for each month with
startWithMonth: moment().add('months', i) ,
but this doesn't seem like an elegant way... Is there a way to do this with only one instance of CLNDR ?

Thanks.

Switching Between 2 Views

Starting with a month view of the calendar, I would like to have it so that when a date is clicked it switches to a week view with the day selected displayed. Kind of like iOS 7 calendar features.

What is the best way of going about this?

Recurring events?

This is amazing! Such great work.
I was wondering if there would be an easy way to let events have a start/end date and to be repeating (i.e. repeat each day, each week etc).

Min and max date

Hi great project.

Is there a way to specify a minimum and maximum date?

Say that I want my calendar to display dates starting from today and only in the coming 6 months.

Alternatively, adding a css class to all dates before today might work.
Something like

<div class="day past calendar-day-2013-10-25">25</div>
<div class="day today calendar-day-2013-10-26">26</div>
<div class="day calendar-day-2013-10-27">27</div>

ID required to be identifier

Having id be the identifier works fine if you only have one calendar. If you have multiple, with proper code, it is not necessarily an issue but functionality could vary by browser.

From the w3c, the 'id' attribute "assigns a name to an element. This name must be unique in a document."

I know we can work around this, for example doing
class="<%= day.classes %> <%= day.id %>"
but we also have to code the logic of parsing the date out of that element, since target.date becomes null

Could an option for which attribute the day.id will be set be implemented?

Great work, though. Very easy to get up and running.

Marking events with different colors

Someone asked me this question directly and I thought it would be useful to post here for others to come across.

If you'd like to show your events with different colors, you'll need some way of distinguishing them within the event data. Let's say our event data has a type:

events = [
  { date: "2013-09-16", title: "Baseball Game", type: "sports" }
]

Now in my template I can ask what the event type is, or better yet I can just dump the event type out as a class and style it accordingly.

<div class="clndr-grid">
  <div class="days">
    <% _.each(days, function(day) { %>
      <div class="<%= day.classes %>" id="<%= day.id %>">
        <div class="number"><%= day.day %></div>
        <% _.each(day.events, function(event){ %>
          <div class="event <%= event.type %>"><%= event.title %></div>
        <% }) %>
      </div>
    <% }); %>
  </div>
</div>

Here each grid box contains a <div> for every event on that day. The class on the <div> is the event's type, which means I can now style .sports { background-color: red; } and specify other colors for other event types.

Can events json be just null ?

Hi,
I am fetching the data for the events from the server and sometimes it just returns null. When it is null clndr.js thorws an error saying this.options.events is null. Is there any way I can resole this ?

Many thanks for your help.

Chintan

Click on Individual Days

Is there currently a way to select an individual day and display only its events to the right (like you have on your website)?

Barring that, the ability to customize the DOM for each date field would be absolutely fantastic.

This is great, thanks!

Events not passed to click event handler with version 1.0.9

I downloaded this repo at version 1.0.6 and was playing with the included demo. Everything worked great as far as I noticed.

I'm now working on a project and just grabbed the latest (1.0.9) for use in it. I noticed that events from my eventsArray are not being passed to my click event handler. I knew this was working when I was playing around with the example before, so as a quick test I stuck version 1.0.9 source into the example for 1.0.6, and the same issue occurred.

Not sure if I'm missing something, but to reiterate, all I did was swap the CLNDR.js source in the example with the recent 1.0.9 and in my click event handler, the events array is always empty when there should be an event associated with that day.

Let me know if you need to see my code or anything else.

thanks.

Other templating libraries

Just wanted to let you know that I've just integrated CLNDR in a project using Handlebars.js. Thanks for the great plugin!

I noticed in a previous PR someone suggested eliminating Underscore as a dependency; I second that thought. Perhaps the current template option functionality could be ported to the render optionโ€”we could detect the type of the value passed in (string vs. function).

Help

Can you please show one example using two different dropdowns - one for month - one for years. Firefox stops working, if I implement that, because of the change/rendered-Status. I need to choose a month, and/or one year. After that events are fired the new Month should be shown. Same behaviour, if next or previous month is selected. Here is the problem. I think the event is fired twice. Please show one example. Thanks!

Recreate First Example on Home Page with CSS

Hi,
@kylestetz, I saw the first example on the home page and immediately recognized that it is perfect for my site (with a few style, orientation, and color tweaks). Could you walk me through how to make this with CSS? I looked at the source code and saw it was LESS (LESS2CSS didn't work very well. It also seems a bit complex. Basically, I need the same thing, just with the events list below it so that it can fit in a sidebar. I looked at the JavaScript portion and saw just how easy it is!

I don't want to sound like I'm asking you to do something for my project specifically, but I do think it would be a good idea to add the calendars shown on the website to the examples on GitHub.

Thanks

Date picker?

Can I use it as a date picker on input fields?

Add year selection

Firstly, thanks for your amazing work. It's not a datepicker, but it has let me build my own in a responsive manner, something which I felt was lacking in whatever else I could find.

However I think it is within the scope of this project to have a bit more integration when it comes to selecting a year. Currently I use doneRendering to add an event listener on a select box I added. Maybe I'm missing a trick with targets and clickEvents?

Scope of callbacks

It would be nice if this inside event callbacks was the calendar object.

var calendar = $("#calendar").clndr({
    clickEvents: {
        click: function () {
            // here 'this' is 'calendar.options.clickEvents'
        }
    },
    doneRendering: function () {
        // here' this' is 'calendar.options'
        // this method is synchronous, so calendar is null
        // the first time it gets called
    }
});

I can have multiple calendars in the page, they have the same behavior on click but they need to access some of the values I specify in extras and the calendar state (like the current displayed month).

I see two solutions

  • pass the calendar object to the callbacks
  • bind the scope to the calendar instance

What do you think?

Any way to show a week view only?

Amazing job you have done!

I would like to ask you if is it already possible to show a week only, not a full month?

Regards :)

EDIT: And the anwser is:

Template

<script type="text/template" id="clndr_template">
    <div class="controls">
        <button class="clndr-previous-button">Prev.</button>
        <div class="month"><%= days[extras.currentWeek * 7].date.format('YYYY-MM-DD') %> - <%= days[extras.currentWeek * 7 + 6].date.format('YYYY-MM-DD') %></div>
        <button class="clndr-next-button">Next</button>
    </div>

    <div class="days-of-the-week clearfix">
        <% _.each(daysOfTheWeek, function(day) { %>
            <div class="header-day"><%= day %></div>
        <% }); %>
    </div>

    <div class="days clearfix">
        <% for(var i = extras.currentWeek * 7; i < extras.currentWeek * 7 + 7; i++) { %>
            <div class="<%= days[i].classes %>" id="<%= days[i].id %>"><%= days[i].day %></div>
        <% } %>
    </div>
</script>

<div id="clndr"></div>

Javascript

function weeksInMonth(month) {
    return Math.floor((month.daysInMonth() + moment(month).startOf('month').weekday()) / 7);
}

var clndr = $('#clndr').clndr({
    template: $('#clndr_template').html(),
    extras: {
        currentWeek: Math.floor( ( ( (moment().date() + moment().startOf('month').weekday() ) - 1 ) / ( weeksInMonth(moment() ) * 7) ) * weeksInMonth( moment() ) )
    },
    doneRendering: function() {

        /* Next button handler */
        $('#clndr .clndr-next-button').on('click', function() {

            /* Get numbers of weeks in the month */
            var weeks_in_month = Math.floor(clndr.month.daysInMonth() / 7) - 1;

            if(clndr.options.extras.currentWeek < weeks_in_month) {
                /* Increase the week count */
                clndr.options.extras.currentWeek += 1;
            } else {
                /* Reset the week count */
                clndr.options.extras.currentWeek = 0;

                /* Go to next month */
                clndr.next();
            }

            clndr.render();
        });

        /* Previous button handler */
        $('#clndr .clndr-previous-button').on('click', function() {

            /* Get numbers of weeks in the month */
            var weeks_in_month = Math.floor(clndr.month.weeks_in_month() / 7) - 1;

            if(clndr.options.extras.currentWeek > 0) {
                /* Decrease the week count */
                clndr.options.extras.currentWeek -= 1;
            } else {
                /* Reset the week count */
                clndr.options.extras.currentWeek = weeks_in_month;

                /* Go to previous month */
                clndr.back();
            }

            clndr.render();
        });

    }
});

Link to URl when event is clicked

I want my events to go to a scpecified URL when they are clicked.
Here is what I have:

var clndr = {};

        $jq( function() {

          var events = [
            { date: '2013-10-10', title: 'Test 1', location: 'Google', url: 'http://www.google.com' },
            { date: '2013-10-19', title: 'Test 2', location: 'Google', url: 'http://www.google.com' },
            { date: '2013-10-23', title: 'Test 3', location: 'Google', url: 'http://www.google.com' },
            { date: '2013-10-07', title: 'Test 4', location: 'Google', url: 'http://www.google.com' }
          ];

          clndr = $jq('#full-clndr').clndr({
            template: $jq('#full-clndr-template').html(),
            events: events,
            clickEvents: {
              click: function(target) {
                window.location.href = target.url;
              }
            },
            adjacentDaysChangeMonth: true
          });
        });

Why doesn't this work?

Consistent number of weeks in a month

First of all, LOVE this project. It's been great. One small suggestion / tweak or I don't know what I'm doing.

screen shot 2013-12-10 at 11 13 39 am

Is their an option for generating and equal number of rows for every month? You can see in the iCal example, they've padded April with an additional row of days from the next month but in the CLNDR example, it's truncated the days on the 4th.

Mixing recurring with single day events

I first tried this in my personal project but tested it with your example file and it's easy to reproduce. Recurring events are shown just fine, but adding a single day event to the eventArray would trigger the actual day (today) to get the "event" class applied and not show the event on the given date at all.

I tried this with your example site.js:

  var eventArray = [
    { startDate: thisMonth + '-03', endDate: thisMonth + '-08', title: 'Multi-Day Event' },
    { startDate: thisMonth + '-21', endDate: thisMonth + '-23', title: 'Another Multi-Day Event' },
    { date: '2013-11-25', title: 'Ow Mah Gawd Single Day'}
  ];

By deleting the multiDayEvents option the single event is shown again.
By deleting all recurring events from the eventArray the "event" class is withdrawn from the actual day (today)
With the multiDayEvents option defined, the described behavior triggers even if there are no recurring events given yet

2 features to be considered

Thanks for CLNDR, such a great cal tool!
I am using it on my site and thought you might consider these 2 features that I added manually.

  • Locking to a specified date, so you can lock your calendar to a specified year or a range, for example 2013-2015. I wanted to have calendar only for 2014 but wanted to keep navigation turned on so you can click on actual days and switch between months but when you come to an end, you then shouldn't be able to navigate through to 2015.
  • I used automatically generated template, wrote my CSS to customise it and now I'd like to inject some data/html into each day cell as it gets rendered. Looks like I would have to use custom template and adjust my styles to the new elements.

Regards
Rad

Document dependencies

Currently, the only dependencies I noticed are:

  • jQuery
  • Underscore.js

But I think I caught a reference to Moment.js? Please document the current requirements in the readme.

Original event in clickCallbacks

Hello again.

I have this use case:

  • Calendar instance inside a dropdown
  • Click listener on the body to hide any dropdown if the target is not in the dropdown
  • clickEvents.click add/remove the selected date in the list of events

Code looks more or less like this

$(".current-month").clndr({
    template: template,
    startWithMonth: today,
    clickEvents: {
        click: function (target) {
            // NOTE: this triggers a calendar refresh
            this.addEvents([{
                date: target.date
            }]);
        }
    }
});

Somewhere else in the application

$("body").click(function (event) {
    var target = $(event.target);
    if (target.parents(".dropdown-container").length) {
        return;
    }
    $(".active").removeClass("active");
});

Now the problem is that by adding a date to the list of events, the calendar is refreshed and the click target gets detached from the DOM. So by the time the event bubbles to the body target.parents(".dropdown-container").length is equal 0 while at the beginning of the click it happened to be 1.

I wanted to have your opinion because I see few options here

  • Handle this specific use case in the body's click listener, so changing the if condition to take care of nodes that are not in the DOM anymore.
  • Call addEvents inside a setTimeout. This way the click bubble correctly, but the code becomes asynchronously ugly.
  • Stop the propagation of the click event. This is my favorite solution because I know that selecting a date consumes the click event, so there's no need to call any other listener

The third solution cannot be implemented because the click callback does not receive the original browser event.

Do you think it makes sense to pass the original browser event to the callbacks in clickEvents?
After all we receive already the DOM element, so the event is a nice companion.

The third solution in looks like this

$(".current-month").clndr({
    clickEvents: {
        click: function (target) {
            target.event.stopPropagation();
            this.addEvents([{
                date: target.date
            }]);
        }
    }
});

Thanks

How to exclude weekends and show only weekdays

Thanks very much for the awesome rabbit hole. Really looking forward to digging deeper into it.

Right now I'm trying to implement a standard 'business days' calendar that shows only the 5 'non-weekend' days which is a common enough task that I think it deserves a passage in the documentation.

Perhaps most of my problem is that I've not needed to use moment.js before but, reading the 'Usage' section i'm puzzled by the passage:

       // an array of day abbreviations. If you have moment.js set to a different language,
        // it will guess these for you! If for some reason that doesn't work, use this...
        // the array MUST start with Sunday
        // (use in conjunction with weekOffset to change the starting day to Monday)
       daysOfTheWeek: ['D', 'L', 'M', 'M', 'J', 'V', 'S'],

It looks like that's a non-English listing of day abbrvs. There's some ambiguity re: starting day 'MUST start with Sunday' and the instruction to use the weekOffset.

And perhaps I'm totally missing the point of 'dayOfTheWeek' - is that intended only to establish the abbreviation to display in the header? I'm looking at it as the way to establish which days to include in the grid. IOW, I'm thinking that:

daysOfTheWeek: ['M', 'T', 'W', 'T', 'F'],

_should give me just the weekdays. Clearly, that's not correct. It begins to look as though I need to understand how to step into the template, detect that a given day is weekend or weekday and render or not render according to that decision.

It'd be very helpful to see how that's accomplished - I'd be more write up something to add to the docs.

Getting numerical representation of the month within template

Hello,

is it possible to get numerical representation of the month inside a template?

Currently the best I could get is -

<a href='/events/month/<%= month.toLowerCase() + '-' + year  %>'>
    <%= month %> <%= year %>
</a>

which turns out to be full textual representation. The problem starts when internationalization is used and the language gets switched. The link is generated in selected language. The most appropriate solution here would be to generate numerical representation of the month which is language agnostic.

I would like to generate, link in format 'yyyy-mm' (2014-04) or 'mm-yyyy' (04-2014).

My current CLNDR version is v1.1.0.

Push unique class to Events day

How to add a unique class to the event day?

<div class="day past calendar-day-2013-12-01" id="">1</div>
<div class="day past event my-event-class calendar-day-2013-12-02" id="">2</div>

or

<div class="day past event start-event-class calendar-day-2013-12-02" id="">2</div>
<div class="day past event calendar-day-2013-12-02" id="">2</div>
<div class="day past event calendar-day-2013-12-03" id="">3</div>
<div class="day past event end-event-class calendar-day-2013-12-04" id="">4</div>

Print day of the week in date block

First of all, thanks for such a great plugin, by far the best calendar plugin around! Just a few niggles though that I'd like to fix (but can't figure out how to). Firstly the day number in each date block, e.g. 1, 2, 3 etc. I'd like these to be 2 digits, preceded with a 0, e.g. 01, 02, 03 etc, if possible?

One more small thing, I'd like to add the date name to each block, so each block would go as follows: Mon 01, Tue 02, Wed 03 etc, if possible?

I have a jsFiddle set up too: http://jsfiddle.net/32EEF/1/
Thanks again for the great plugin!

Multiple calendars on a page

I'm trying to wrap my head around it, but I can't seem to think of a way to get multiple calendars with different events on a single page to work. Any pointers?

customizing day.classes

Hi there, love this plugin. May I know how I could customize the the day.classes for each day inside the days array?

Lets say for example I have a calendar with a few days to 'blackout'. So these days will never have any events on them. I would like to customize a .blackout class to be shown on the generated calendar.

is that possible?

FF & Safari bug

Events aren't getting populated in ff & safari. Something to do with Moment & the Date object I'm sure; chrome is more forgiving about date formatting.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.